> ## Documentation Index
> Fetch the complete documentation index at: https://www.marqeta.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# How to migrate UX Toolkit SDK to dedicated OAuth

<Warning>
  **Warning**<br />Migrating your UX Toolkit SDK to dedicated OAuth is **required** if you are on version 1 of the UX Toolkit and wish to upgrade to version 2
</Warning>

Marqeta is issuing a new client ID for your program so you can mint machine-to-machine access tokens at a dedicated authorization host instead of the UX Toolkit API host. This guide covers everything you need to change to complete the switch.

## Before you begin

* You'll need the new client ID Marqeta issues for your program, along with the key ID (kid) for your public key — request them from your Marqeta representative if you don't have them yet.
* Your existing signing key, scope, and token audience  do not change as part of this migration.
* Your current setup keeps working until you switch over, so you can test the dedicated flow without a hard cutover.

## Steps

#### **Step 1 - Update your Customer Auth API service.**

Once you've requested and received your new client ID from your Marqeta representative, you'll need to update your custom Auth API service. This service mints (or proxies) the access token the SDK uses.

1. **Point the token request at the dedicated host.** Send POST /oauth/token to the dedicated host for your environment (see [Endpoints by environment](#endpoints-by-environment)).
2. **Rebuild the client assertion.** The client\_assertion is a JWT signed with your existing private key. <br /><br />The following changes to the **Header**:<br /><br />The JWT **header** must now carry a 'kid' - the key ID Marqeta provides alongside your new client ID. It tells the dedicated host which of your registered public keys to verify the signature against. <br /><br />The following changes need to be made to the **payload** (see [Token exchange reference](#token-exchange-reference)):
   1. "iss" and "sub" change from your current ID to your new client ID.
   2. "aud" changes to include the full endpoint, not just the bare host
   3. "exp" is now capped at 5 minutes — the dedicated host rejects any assertion whose "exp" is more than 300 seconds after "iat".
   4. "exp" changes to 1717000300 and will now be capped at 5 minutes, anything longer will be rejected.
      ```text focus={4-5,7,10} theme={null}
      {
      -   "iss": "<the client id you use today>",
      -   "sub": "<the client id you use today>",
      +   "iss": "<your new client ID>",
      +   "sub": "<your new client ID>",
      -   "aud": "https://ux-toolkit-api.marqeta.com",
      +   "aud": "https://secure.marqeta.com/oauth/token",
          "iat": 1717000000,
      -   "exp": 1717000600,    
      +   "exp": 1717000300,     
      }
      ```

<Note>
  **Note**<br />**Leave audience pointed at the UX Toolkit API.** The audience form parameter does not change,  — it stays the UX Toolkit API host for your environment, but the trailing slash is removed from the end. The token is minted by the dedicated host but intended for the UX Toolkit API. Don't confuse this with the assertion's aud claim above; they are different values.
</Note>

3. **Forward the DPoP proof unchanged.** Your Customer Auth API service still receives the SDK's DPoP header and forwards it on the upstream token request — you don't generate or modify it. Its htu must match the dedicated host.
   ```text theme={null}
   POST https://secure.marqeta.com/oauth/token
   DPoP: <the DPoP proof from the SDK, forwarded unchanged>
   Content-Type: application/x-www-form-urlencoded
   grant_type=client_credentials
   client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer
   client_assertion=<signed JWT above>
   audience=https://ux-toolkit-api.marqeta.com   	# remove trailing "/" from URL
   user_token=<cardholder user token>            		# cardholder tokens only
   ```

#### Step 2 - Start using V2 of the UX Toolkit SDK

Upgrade to Version 2 by changing the major version in the script tag that loads the SDK, where `prgmshrtcde` is your program short code:

`https://web.ux-toolkit.marqeta.com/prgmshrtcde/releases/2/index.js`

Version 2 mints from the dedicated host by default and automatically binds the DPoP proof's htu to the dedicated token endpoint. Changing to the v2 url is the entire change on the SDK side, your app keeps calling the SDK exactly as it does today.

## Verify it worked

* Keep both paths behind a switch — have your Customer Auth API service select the host by config or a request flag, so you can flip back instantly if needed.

* Verify in sandbox: point your Customer Auth API service at your new sandbox client ID, upgrade the SDK, mint a token, and confirm the SDK renders live data. Exercise both cardholder and administrative scopes if you use them.

* Promote to production with your new production client ID. You're successful when SDK successfully mints a token from the dedicated host and renders live data for both cardholder and administrative scopes (if used), with no 401 errors on token refresh.

* Once traffic is fully on the dedicated flow, ask Marqeta to decommission your previous credential.

## Token exchange reference

| **Parameter**            | **Now**                                                                    | **Change to**                                                                    | **Status** |
| :----------------------- | :------------------------------------------------------------------------- | :------------------------------------------------------------------------------- | :--------- |
| Token endpoint           | [https://ux-toolkit-api.marqeta.com](https://ux-toolkit-api.marqeta.com)   | [https://secure.marqeta.com/oauth/token](https://secure.marqeta.com/oauth/token) | Change     |
| Assertion iss / sub      | The client ID you use today                                                | Your new client ID                                                               | Change     |
| Header kid               | Not sent                                                                   | The key ID Marqeta provides for your public key                                  | Change     |
| Signing key              | Your existing key                                                          | Unchanged                                                                        | Keep       |
| Assertion aud            | Host only                                                                  | Full secure.\*/oauth/token URL                                                   | Change     |
| Assertion exp            | Up to \~10 min                                                             | ≤ 5 min (iat + 300s)                                                             | Change     |
| audience (form)          | [https://ux-toolkit-api.marqeta.com/](https://ux-toolkit-api.marqeta.com/) | [https://ux-toolkit-api.marqeta.com](https://ux-toolkit-api.marqeta.com)         | Change     |
| grant\_type              | client\_credentials                                                        | client\_credentials                                                              | Keep       |
| client\_assertion\_type  | …jwt-bearer                                                                | …jwt-bearer                                                                      | Keep       |
| DPoP required            | Yes                                                                        | Yes                                                                              | Keep       |
| user\_token (cardholder) | In request body                                                            | In request body                                                                  | Keep       |

## Endpoints by environment

Mint at the dedicated host; keep audience set to the UX Toolkit API host for the same environment.

### **Sandbox**

* Mint at: [https://secure-sandbox.marqeta.com/oauth/token](https://secure-sandbox.marqeta.com/oauth/token)
* Audience: [https://ux-toolkit-api-sandbox.marqeta.com](https://ux-toolkit-api-sandbox.marqeta.com)

### **Production**

* Mint at: [https://secure.marqeta.com/oauth/token](https://secure.marqeta.com/oauth/token)
* Audience: [https://ux-toolkit-api.marqeta.com](https://ux-toolkit-api.marqeta.com)

Test in sandbox first. Confirm both a cardholder and (if used) an administrative token mint and call successfully before promoting to production.

## Common issues

* **401 invalid\_client with a bare host in the assertion aud**
  * The assertion aud must be the full token-endpoint URL (.../oauth/token), not just [https://secure.marqeta.com](https://secure.marqeta.com). Watch for URL-normalizers that quietly strip the path.
* **401 invalid\_client after previously working**
  * The assertion lifetime is capped at 5 minutes. The dedicated host rejects any client\_assertion whose exp exceeds iat + 300 seconds. Mint the assertion fresh per request rather than reusing a longer-lived one.
* **DPoP proof rejected**
  * The proof's htu must match the endpoint actually hit. If htu still points at the UX Toolkit API host while the request goes to the dedicated host, the proof is rejected. Upgrading to SDK v2 keeps htu and the request target in sync so this works.

## Related articles

* \[UX Toolkit SDK v2 upgrade notes]
* \[DPoP proof-of-possession reference]
