Configure your authorization server
Trust AIGW from Keycloak or any OAuth server with RFC 7523 or RFC 8693.
Checked against the Evaluation environment, Console 0.10.1 / 0.14.1, on October 19, 2026. Release status
This guide is for the team that runs the merchant's authorization server (AS). AIGW does not ask your API to trust the agent's AIGW token. Instead, AIGW gets a token from your existing AS, and only your MCP or UCP service sees that merchant token. Your job is to make your AS trust AIGW and to decide how AIGW users map to your users.
How AIGW reaches your server
Each Token exchange Resource in the AIGW Console has its own issuer and its own ES256 signing key. With the default method, your AS needs two trust relationships with that Resource:
- Trust the Resource as an assertion issuer. AIGW sends a user assertion signed with ES256 by the per-resource issuer, verifiable at the per-resource JWKS.
- Trust AIGW as a client. AIGW authenticates as the client you registered for it, using a JWT client assertion signed by the same Resource key.
Your AS also has to:
- accept your own issuer URL, as configured on the Resource, as the JWT
aud; - define every scope name AIGW will request;
- map the assertion
subto a merchant user, or link or provision that user under your policy; - issue an access token your backend accepts.
Choose a method
The method is set in the Resource's Client authentication field. It decides what AIGW sends to your token endpoint.
| Console value | What AIGW sends | Status |
|---|---|---|
private_key_jwt | RFC 7523 JWT bearer user assertion plus JWT client authentication. The default, and the method the Keycloak walkthrough uses. | Supported with the Playground's preconfigured Keycloak Resource. Unverified on a newly configured Resource. |
token_exchange | RFC 8693 token exchange with an external, AIGW-signed subject token and JWT client authentication. | Unverified |
client_secret_basic | Client ID and secret over HTTP Basic. The Console collects a secret for it. | Unsupported Use private_key_jwt instead. |
Values you receive
Whoever operates the AIGW Resource (you, or your MCP or UCP provider) hands you these values. They are on the Resource's Reference step and at the bottom of its Configuration tab.
| Value | What you use it for |
|---|---|
| Per-resource issuer | Trusted assertion issuer, for example https://api.aigw.eval.loginid.ai/<RESOURCE_ID> |
| Per-resource JWKS URL | Verifying the ES256 assertions, for example https://api.aigw.eval.loginid.ai/<RESOURCE_ID>/.well-known/jwks.json |
| Client ID | Identifies AIGW at your AS. You create this client; AIGW stores the same value. |
| Requested scopes | The permissions AIGW may request. Each must exist in your AS. |
| Merchant issuer URL | Your AS issuer. It must match the Resource configuration and is the assertion audience. |
| Merchant token endpoint | Where AIGW sends the grant. |
Keycloak 26
This walkthrough uses Keycloak 26.x and the private_key_jwt method: an RFC 7523 JWT bearer grant for the user plus Signed JWT client authentication for AIGW. Do not swap in Keycloak's Standard Token Exchange. In its standard mode it does not accept the external AIGW-signed subject token, so the RFC 7523 path is the one to use.
Before you start, have the Resource issuer, the Resource JWKS URL, the Client ID set on the Resource, the requested scopes, and your realm issuer and token endpoint ready.
Add a JWT Authorization Grant identity provider
Who: Merchant IAM admin
In Keycloak, open Identity providers, choose Add provider, then JWT Authorization Grant.
| Field | Value |
|---|---|
| Alias | A unique alias for this AIGW Resource, for example aigw-demo-search-api |
| Issuer | The AIGW per-resource issuer |
| Use JWKS URL | On |
| JWKS URL | The AIGW per-resource JWKS URL |
| Max allowed assertion expiration | 1 hour |
| Assertion signature algorithm | ES256 |
| Allow assertion reuse | Off |
| Allowed clock skew | 60 seconds |
After saving, reopen the provider and confirm it still points at the intended issuer and JWKS URL.
One identity provider per Resource
The AIGW issuer is per Resource. Do not reuse the provider you made for Resource A on Resource B. The add form may prefill the alias jwt-authorization-grant; replace it so aliases never collide.
Create the client AIGW uses
Who: Merchant IAM admin
Open Clients, choose Create client, and pick OpenID Connect. The Client ID must match the Client ID on the AIGW Resource exactly.
| Capability config | Value |
|---|---|
| Client authentication | On |
| Standard flow | Off. This is a back-channel client. |
| JWT Authorization Grant | On |
| Allowed identity providers for JWT Authorization Grant | The alias from the previous step |
Configure Signed JWT client authentication
Who: Merchant IAM admin
On the client's Credentials tab:
| Setting | Value |
|---|---|
| Client Authenticator | Signed JWT |
| Signature algorithm | ES256 |
| Max expiration | 1 minute |
When Keycloak asks Change to client-jwt?, confirm. If you skip the prompt, the new authenticator is not saved.
Then, on the Keys tab, turn Use JWKS URL on and enter the same AIGW Resource JWKS URL. With a URL instead of a pasted key, Keycloak fetches the new key when AIGW rotates to a new kid.
Map the custom audience
Who: Merchant IAM admin
AIGW sets the assertion aud to the Issuer URL configured on the Resource, which is your realm issuer. Open the client's Advanced tab, then OpenID Connect Compatibility Modes, then Custom audience mapping, and map the identity provider alias to the realm issuer.
# <IdP alias> -> <realm issuer>aigw-demo-search-api -> https://id.example.com/realms/shopWithout this mapping Keycloak rejects the JWT for its audience.
Create and attach merchant scopes
Who: Merchant IAM admin
For every scope requested on the AIGW Resource, create a Keycloak client scope with the same protocol value. For search:read:
| Client scope field | Value |
|---|---|
| Name | search:read |
| Type | None |
| Protocol | OpenID Connect |
| Include in token scope | On |
Then open the AIGW client and attach the scope as Optional. Type None keeps the scope from becoming a realm-wide default for unrelated clients. Include in token scope defaults to Off, so check it.
Point the AIGW Resource at Keycloak
Who: Resource operator
In the AIGW Console, open the Token exchange Resource's Configuration tab and set:
Issuer URL https://id.example.com/realms/<realm>Token endpoint https://id.example.com/realms/<realm>/protocol/openid-connect/tokenClient ID <the exact Client ID of the Keycloak client>Method private_key_jwtSave, reload the page and confirm every value persisted.
Decide how users are matched
Who: Merchant IAM admin
This is the step most likely to block your first real exchange. A new JWT Authorization Grant provider starts with no linked users, so AIGW's assertion sub has to resolve to someone. Pick one approach:
- pre-link known users to the identity provider;
- map email to an existing Keycloak user;
- auto-create or link users through a custom flow or extension;
- reject unknown users.
The reference setup linked its test user to the provider with a federated identity link whose external user ID matched the AIGW subject. Auto-provisioning on a newly created provider is Unverified, so test it before you depend on it. The resolution order is under How users are resolved.
Common Keycloak problems
| Problem | Why it happens | Fix |
|---|---|---|
| Identity provider alias collision | The add form prefills jwt-authorization-grant | Use a unique alias per Resource. |
| A new scope never appears in tokens | Include in token scope defaults to Off | Turn it on. |
| A scope is assigned to every client | Client scope Type was set to Default or Optional at creation | Set Type to None, then attach it explicitly. |
invalid_client | Signed JWT, JWKS, algorithm or lifetime mismatch | Recheck the client's Credentials and Keys tabs. |
invalid_grant with user not found | No mapping or link for the assertion sub | Configure user mapping or provisioning. |
| JWT rejected for its audience | Custom audience mapping is missing | Map the alias to the realm issuer. |
| Key rotation breaks verification | Keycloak holds a static key instead of the JWKS URL | Configure the Resource JWKS URL. |
Any other OAuth server
If you don't run Keycloak, implement one of these two contracts. Equivalent verified console walkthroughs for Auth0 and Okta are not available for this release, so this section describes the protocol only.
Option A: RFC 7523 JWT bearer (private_key_jwt)
AIGW sends two JWTs to your token endpoint, both signed ES256 with the Resource signing key: a user assertion used with the JWT bearer grant, and a client assertion for JWT client authentication.
POST <merchant token endpoint>Content-Type: application/x-www-form-urlencodedgrant_type=urn:ietf:params:oauth:grant-type:jwt-bearer# plus the ES256 user assertion and a JWT client assertion (RFC 7523)Only the grant type is documented for this release. The other form parameter names are expected to follow RFC 7523 but are Unverified.
iss = https://api.aigw.eval.loginid.ai/<RESOURCE_ID>sub = external user reference (email candidates, then the AIGW subject)aud = <merchant issuer URL configured on the Resource>iat = nowexp = now + assertion lifetimejti = unique UUIDiss = <merchant AS client ID>sub = <merchant AS client ID>aud = <merchant issuer URL configured on the Resource>iat = nowexp = now + assertion lifetimejti = unique UUIDOption B: RFC 8693 token exchange (token_exchange)
Unverified AIGW can instead send a token exchange request with JWT client authentication:
POST <merchant token endpoint>Content-Type: application/x-www-form-urlencodedgrant_type=urn:ietf:params:oauth:grant-type:token-exchangesubject_token=<AIGW-signed subject token>subject_token_type=urn:ietf:params:oauth:token-type:jwtrequested_token_type=urn:ietf:params:oauth:token-type:access_tokenresource=<resource indicator>scope=<requested scopes># plus JWT client authenticationYour AS must accept an external subject token
The subject token is signed by AIGW, not by your AS. Do not assume a product's standard token exchange feature accepts external subject tokens. Keycloak's standard mode does not for this pattern.
Scope and response contract
- Every scope AIGW requests should exist in your AS and map to the permission your API expects. AIGW sends the requested scope string, intersected with what is allowed, to your token endpoint.
- On success, return a standard OAuth access token response.
- In RFC 8693 mode, also return
issued_token_typeset to the access token type and a meaningfultoken_type.
Trust the Resource JWKS
AIGW signs merchant-facing assertions with a per-Resource EC P-256 key (ES256). A first key is generated when the Resource is created, so the JWKS URL works immediately. Check that your AS can reach it:
curl -s "https://api.aigw.eval.loginid.ai/<RESOURCE_ID>/.well-known/jwks.json"- Configure the JWKS URL, not a pinned public key. When the operator creates a new signing key, it becomes active and older keys stay in the JWKS during rotation.
- Select keys by
kidand refetch the JWKS when you see an unknownkid. - Don't confuse this key set with the core JWKS at
https://core.api.aigw.eval.loginid.ai/.well-known/jwks.json. The core set signs agent-facing AIGW access tokens. Your AS trusts the per-resource set only.
How users are resolved
AIGW tries sub candidates in this order:
- each email available from the user's login evidence, in order;
- the AIGW pairwise subject.
It moves to the next candidate only when your AS returns invalid_grant with an error description containing user not found. Any other error stops the sequence. So decide what your user identifier is: if you match on email, make sure your grant implementation really resolves users by email; if you require federated links, create them or provision them.
Test your setup
Check each layer on its own before you run a full flow:
- Your AS can fetch the Resource JWKS.
- The AIGW client authenticates with Signed JWT and ES256.
- The audience mapping points the alias, or your audience check, at your issuer.
- Every requested scope exists and is attached to the client.
- The target user resolves from the assertion
sub. - The Resource issuer, token endpoint and Client ID match your AS exactly.
- Your maximum expiration rules accept the assertion lifetime.
Then run a real end-to-end flow: an agent authorizes, and the MCP or UCP service redeems the merchant token. The Playground runs that flow in your browser.
The Console Test exchange button produces no result
Unsupported The Test exchange button on the Resource's Reference step and Configuration tab shows no result in this release. Test with a real flow or the Playground instead.
Redemption is Supported with the Playground's preconfigured private_key_jwt Keycloak Resource. A full exchange against a Resource you configure yourself is Unverified, so test yours end to end before production.

