Widgets V2 Getting Started
Create a Widgets V2 widget in Admin Portal and request a widget URL from your backend, for sandbox and live widgets.
Widgets V2 Getting Started
Widgets V2 are embeddable widgets that run in an iframe on your site or app. This guide takes you from creating a widget in the Admin Portal to requesting a widget URL from your backend.
You will need:
- Access to the Admin Portal with API → Widgets V2 enabled for your account. Contact your Moneyhub representative if you cannot see it.
- An API business linked to your Admin Portal user.
Step 1 — Create a widget
- In the Admin Portal, go to API → Widgets V2 and select Add new Widget V2.
- Choose the Widget type.
- Enter a Name. This is for your reference in Admin Portal only.
- Choose the Business linkage — the API business the widget belongs to.
- Choose the Status:
- Sandbox — the widget runs against sandbox data. Use this while you build your integration.
- Live — the widget runs against live data for your real users.
- For
connections-widgetandaffordability-widget, check the Redirect URIs. See Redirect URIs. - Adjust the widget's configuration if needed, then select Save.
Status is permanentYou cannot change a widget's status after it is created. To move from sandbox to live, create a new Live widget.
Open the widget from the list and note its Widget ID and Type. You need both to request a widget URL.
Redirect URIs
connections-widget and affordability-widget take the user through a bank connection. After the user authorises with their bank, they are sent back to a redirect URI, which must be registered on the widget.
The Redirect URIs field is pre-filled with the Moneyhub-hosted widget page, which is the default. To send users back to your own site or app instead, add its URLs, separated by commas. Each URL must use HTTPS. Paths are allowed, but query strings and fragments are not.
You can change the redirect URIs later in the Configuration section of the widget detail page. Other widget types do not use redirect URIs, so the field is not shown for them.
The next steps depend on the status you chose:
- Sandbox widgets authenticate with a client secret.
- Live widgets authenticate with a signed JWT, so you first create a key pair.
Sandbox widgets
Step 2 — Create a sandbox launch client
A launch client is the API client your backend uses to request widget URLs.
- On the widget detail page, select Create new launch client.
- Set Launch client type to Sandbox (client secret).
- Enter a Name and select Create.
To find the client's credentials, go back to API → Widgets V2 and open the client from the launch clients list. Note the Client ID and Client secret.
Step 3 — Request a widget URL
From your backend, call the auth-url endpoint. Replace the placeholders with your values; widgetType in the path must match the widget's Type.
curl -X POST "https://widget-pages.moneyhub.co.uk/api/{widgetType}/auth-url" \
-H "Content-Type: application/json" \
-d '{
"widgetId": "YOUR-WIDGET-ID",
"clientId": "YOUR-LAUNCH-CLIENT-ID",
"clientSecret": "YOUR-LAUNCH-CLIENT-SECRET",
"params": {}
}'Continue to Use the widget URL.
Live widgets
Live launch clients do not use a client secret. Your backend proves its identity by signing a short-lived JWT, called a client assertion, with a private key. Moneyhub checks it with the matching public key, which you register in Admin Portal.
The examples below use Node.js 18 or later and need no extra packages.
Step 2 — Create a key pair
Save this script as create-jwks.mjs and run it with node create-jwks.mjs:
import crypto from "node:crypto"
import fs from "node:fs"
const {publicKey, privateKey} = crypto.generateKeyPairSync("rsa", {modulusLength: 2048})
const publicJwk = publicKey.export({format: "jwk"})
// The key ID is the key's RFC 7638 thumbprint
const {e, kty, n} = publicJwk
const kid = crypto.createHash("sha256").update(JSON.stringify({e, kty, n})).digest("base64url")
const keyDetails = {kid, use: "sig", alg: "RS256"}
const publicJwks = {keys: [{...publicJwk, ...keyDetails}]}
const privateJwks = {keys: [{...privateKey.export({format: "jwk"}), ...keyDetails}]}
fs.writeFileSync("public-jwks.json", JSON.stringify(publicJwks, null, 2))
fs.writeFileSync("private-jwks.json", JSON.stringify(privateJwks, null, 2), {mode: 0o600})
console.log(JSON.stringify(publicJwks, null, 2))It writes two files in the same format as the Moneyhub API client's create-jwks script:
public-jwks.json— your public JWKS. This is safe to share and is what you register in Admin Portal.private-jwks.json— your private key. Store it securely on your backend, for example in a secrets manager. Never share it, commit it to source control, or send it to the browser or to Moneyhub.
Step 3 — Add the public JWKS to a launch client
A launch client is the API client your backend uses to request widget URLs. For a live widget, it holds your public JWKS.
- On the widget detail page, select Create new launch client.
- Set Launch client type to Production (private key JWT).
- Enter a Name.
- Paste the contents of
public-jwks.jsoninto Public JWKS. - Select Create.
Go back to API → Widgets V2, open the client from the launch clients list, and note its Client ID.
Step 4 — Activate the launch client
Production launch clients are not live as soon as you create them. A Moneyhub administrator must set the client's status to Live before you can request widget URLs for a Live widget.
- Contact your Moneyhub representative and share the launch client's Client ID and Name.
- Wait for confirmation that the client has been activated.
- Optionally, open the client in API → Widgets V2, follow Advanced client configuration, and check that Status shows Live.
Do not call auth-url for production until this step is complete.
Step 5 — Create a client assertion
Sign a new client assertion each time you request a widget URL. Each assertion is single-use and expires after 300 seconds.
Save this script as create-client-assertion.mjs, set launchClientId to your launch client's Client ID, and run it with node create-client-assertion.mjs:
import crypto from "node:crypto"
import fs from "node:fs"
const launchClientId = "YOUR-LAUNCH-CLIENT-ID"
const issuer = "https://identity.moneyhub.co.uk/oidc"
const [privateJwk] = JSON.parse(fs.readFileSync("private-jwks.json", "utf8")).keys
const encode = (value) => Buffer.from(JSON.stringify(value)).toString("base64url")
const now = Math.floor(Date.now() / 1000)
const header = {alg: "RS256", typ: "JWT", kid: privateJwk.kid}
const claims = {
iss: launchClientId,
sub: launchClientId,
aud: issuer,
jti: crypto.randomUUID(),
iat: now,
exp: now + 300,
}
const signingInput = `${encode(header)}.${encode(claims)}`
const privateKey = crypto.createPrivateKey({key: privateJwk, format: "jwk"})
const signature = crypto.sign("sha256", Buffer.from(signingInput), privateKey)
console.log(`${signingInput}.${signature.toString("base64url")}`)The script prints the signed client assertion. The claims it uses are:
| Claim | Value |
|---|---|
iss, sub | Your launch client ID |
aud | The Moneyhub Identity issuer, https://identity.moneyhub.co.uk/oidc |
jti | A unique ID for each assertion |
iat, exp | Issued-at time, and an expiry 300 seconds later |
Step 6 — Request a widget URL
From your backend, call the auth-url endpoint with the client assertion. Replace the placeholders with your values; widgetType in the path must match the widget's Type.
CLIENT_ASSERTION=$(node create-client-assertion.mjs)
curl -X POST "https://widget-pages.moneyhub.co.uk/api/{widgetType}/auth-url" \
-H "Content-Type: application/json" \
-d '{
"widgetId": "YOUR-WIDGET-ID",
"clientId": "YOUR-LAUNCH-CLIENT-ID",
"tokenEndpointAuthMethod": "private_key_jwt",
"clientAssertion": "'"$CLIENT_ASSERTION"'",
"clientAssertionType": "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
"params": {}
}'Use the widget URL
A successful request returns the widget URL:
{
"data": {
"widgetUrl": "https://..."
}
}Pass widgetUrl to your frontend and set it as the src of an iframe:
<iframe
src="WIDGET_URL_FROM_YOUR_BACKEND"
title="Moneyhub widget"
style="width: 100%; height: 720px; border: none;"
></iframe>The URL contains a short-lived token, so load it straight away and request a new one for each user session.
Showing a user's data
To show a specific user's data, add "sub": "MONEYHUB-USER-ID" to the auth-url request body. This works for both sandbox and live widgets. The user must belong to the same API business as the widget and launch client. To create a user and get their user ID, see API Users. Without sub, the widget runs with client-level access only. connections-widget and affordability-widget always need sub.
Choosing a redirect URI
For connections-widget and affordability-widget, you can add "redirectUri": "https://your-site.example/callback" to the auth-url request body to choose where the user returns after connecting their bank. It must exactly match one of the widget's redirect URIs. If it does not, the bank connection fails with an invalid_redirect_uri error. Without redirectUri, the user returns to the Moneyhub-hosted widget page.
Keep credentials on your backendAlways call auth-url from your server. Never put your client secret, private key, or client assertions in frontend code.
Updated 4 minutes ago
