Skip to main content
Your service account normally calls platform APIs as your app. It does not represent a specific merchant user. With on-behalf-of authentication, your backend can exchange a service account token for a token that represents a specific merchant user. API calls made with that token are authorized using that user’s JTL-Wawi permissions. This is useful when an agent or backend process needs to act for a person. Instead of giving it your app’s broader access, you can have it operate with the same permissions as the user it is acting for. An on-behalf-of token cannot give your app more access than the user has. The gateway enforces the user’s permissions, so your app does not need to manage those roles itself. If your backend only ever acts as your app, keep using your access token. See Service Account Authentication.

How It Works

Your app does not create the on-behalf-of token itself. It first authenticates with its service account, then sends that access token to the Account Service to request a token for a specific user. When the Account Service receives the request, it checks:
  • Your app is installed for the specified tenant.
  • The capability is enabled for your app.
  • The specified user belongs to that tenant.
If any of these checks fail, the request is rejected. If they pass, the Account Service returns an on-behalf-of token that your app can use to call JTL Cloud APIs as that user.

Before You Start

Three things need to be in place.
1

Enable the capability

Your app’s service account declares it in the app manifest:
You can also turn on Act on behalf of users on the service account in the Partner Portal.
2

Have your service account credentials

The CLIENT_ID and CLIENT_SECRET issued when you registered your app. See Service Account Authentication.
3

Know the user and the tenant

You name the user by their JTL ID and the tenant by its ID. Both come from a verified token:An embedded app reads these from the app token its frontend sends. An app on its own domain reads them from the token it receives at sign-in. See App Token Authentication and Standalone Authentication.You do not need the user’s own token at exchange time, only their ID. Your app must be installed for the tenant, and the user must be a member of it.

Getting an On-Behalf-Of Token

The exchange takes two calls: one to authenticate as your app, one to swap that credential for a user-bound token.
1

Get your access token

Request a client_credentials token as you would for any other API call.
2

Exchange it for a user-bound token

Send the access token as the bearer, and name the user and tenant in the body.
The response carries the token, a refresh token, and its lifetime in seconds.
3

Call the API as the user

Use accessToken as the bearer, and send the same tenant you named in the exchange.

Implementation

The exchange in each language, taking the access token from your service account and returning a token bound to the user.

Refreshing the Token

For long-running or unattended work, rotate the token with its refresh token rather than running the exchange again.
The bearer is your service account’s access token, the same one you used for the exchange. Store the new refresh token and discard the old one. Rotation re-checks that your app is still installed for the tenant and the capability is still enabled, so uninstalling the app or turning it off ends the delegation. A refresh token cannot outlive your app’s access.
A refresh token is single use. Once rotated, the previous one is invalid, so a stored copy left over from an earlier rotation fails with 400.

Token Claims

The on-behalf-of token is a JWT you use as a bearer. Its subject is the user, so services authorize as the user, while the delegation stays visible in the claims. The tenant is fixed when the token is minted, so a token issued for one tenant cannot be used against another.

Errors

The failures you are most likely to hit, and what causes them.
No service account token reached the endpoint. The exchange authenticates as your app, so your access token belongs in the Authorization header of the exchange request itself, not only on the calls you make afterwards.
The access token was issued without an app identity behind it. Confirm the app and its service account are registered in the Partner Portal, and that the credentials you are using belong to that app.
Two checks produce this. Confirm Act on behalf of users is enabled on your app’s service account, and that the merchant has installed your app on the tenant you named.
The userId and tenantId do not belong together. Take both from the same verified app token, where sub is the user and urn:jtl:tenant_id is their tenant, rather than combining values from different sources.
The refresh token is invalid, expired, revoked, or has already been rotated. Rotation invalidates the previous token immediately, so a stored copy from an earlier rotation fails. Run the full exchange again to get a new pair.
The token is valid, but the call exceeds what the user is permitted to do. An on-behalf-of token is bounded by that user’s own JTL-Wawi permissions, so a merchant without write access to a resource cannot write to it through your app. See Scopes & Permissions.

What’s Next?

Service Account Authentication

Obtain and cache the access token this exchange starts from.

App Token Authentication

Verify the app token that tells you which user and tenant to act for.

Scopes & Permissions

How enforcement differs between an access token and a user-bound token.

Using Platform APIs

Call the JTL Cloud and JTL-Wawi APIs with the right headers and scoping.