Sign-in and verification
Identity Broker API
Federates sign-in to external identity providers: social logins, enterprise OIDC / OAuth / SAML, and national eIDs such as DigiD, eHerkenning and eIDAS. The management API configures those providers; the broker's OIDC endpoints are what Access and IO call at sign-in.
https://{tenant-host}/brokeraudience identity-broker53 operationsWhen to use it
- List, create or change the external identity providers of a tenant from a backend or a pipeline.
- Read a provider's alias and variants before wiring it into a journey.
- Fetch and check an IdP's OIDC or SAML metadata before you save a configuration.
- Upload the signing or encryption credentials a SAML or eID provider needs.
Connect
- Base URL
https://{tenant-host}/broker- Token
POST https://{tenant-host}/oauth/v1/tokenwithgrant_type=client_credentials. The client ID and secret go in the form body.checked live- Client to create
- Access admin → Web clients → a client with the grant type Client credentials. Not an API client: those are only for Access's own configuration API.checked live
- Default audiences
- must include the broker's audience. The service code's default is
identity-broker; older notes and tools usebroker. Neither has been seen working on a tenant yet. Test one without calling the broker: addaudience=identity-brokerto the token request. A 400invalid_requestmeans the client doesn't have it.from source - Default scopes
broker:getfor reads,broker:postfor writes. The service maps them to the rolesrole_broker_readandrole_broker_writethat the published spec names. Tenants checked so far define no broker scopes in Access: add them under Access admin → Scopes first.from source- Refusals
- Every authorization failure is 401, with an empty body: a wrong audience and a missing scope look the same. There is no 403. A token without the audience was seen getting exactly that.from source
- Discovery
GET https://{tenant-host}/broker/.well-known/openid-configurationneeds no token. Issuer ishttps://{tenant-host}/broker; the only grant isauthorization_code; clients authenticate withprivate_key_jwtorclient_secret_post.checked live
curl -s https://{tenant-host}/oauth/v1/token \
-d grant_type=client_credentials \
-d client_id=$CLIENT_ID \
-d client_secret=$CLIENT_SECRET
curl -s https://{tenant-host}/broker/api/v1/configuration \
-H "Authorization: Bearer $ACCESS_TOKEN"Operations
Open an operation to see its parameters and code, and send it to your tenant. The token needs any one of the listed scopes. Discovery and JWKS need no token. The browser endpoints (/broker/authorize, /broker/token, /broker/userinfo, /broker/end_session) are for relying parties at sign-in and are not listed here.
Connect to your tenant
Then open any operation below and send it.Sends grant_type=client_credentials to https://{tenant-host}/oauth/v1/token through this site's server. The secret and token stay in this tab only; host and client ID are remembered.
What trips people up
A missing scope is 401, not 403
from sourceThe broker answers 401 to every authorization failure, including a token that has the audience but lacks broker:get / broker:post. The body is empty. Check the token's aud and scope claims before blaming the secret.
Send broker:get / broker:post, not role_broker_read / role_broker_write
from sourceThe published spec names role_broker_read and role_broker_write. Those are internal roles. A client-credentials token gets them from the scopes broker:get and broker:post.
GET /api/v1/configuration is a plain list
from sourceIt returns an array of overviews (id, name, alias, type, active, domainAliases, variants), not a paged object. Variants in the overview carry name and acrValue only: read the typed endpoint for variant ids and aliases.
PUT replaces the whole configuration
from sourcePUT is not a merge. GET the provider, change what you need and send every required field back, keeping variant ids. For OIDC the GET reply is shaped differently from the PUT body (it nests relyingParty and identityProvider), so don't send it back unchanged.
Reads never return secrets
from sourceProvider reads leave client and shared secrets out; relying-party settings show ******. Never send the mask back as a secret. Keep the real value in your secret store and send it when a PUT needs it.
Create returns 201 for SAML but 200 for OIDC
from sourceAccept any 2xx on create. Use the returned alias: the broker derives it from the name (lower-case, accents and punctuation removed) and adds a number when it is taken.
DELETE answers 204 even when nothing was deleted
from sourceA second delete of the same provider is still 204. Confirm with the list instead of trusting the status.
Metadata fetches are restricted
from sourceThe *-metadata helpers refuse private, loopback, link-local and cluster-internal addresses, don't follow redirects, refuse compressed replies and stop at 1 MiB. Point them at the IdP's public URL. A successful fetch does not save anything.
Read back before retrying a failed write
from sourceA create or update can fail after the database save. Read the configuration back before sending the same create again, or you get a 409 for the name.
Errors
Management errors carry id, code, message and details (often null). The status is the number in the code. 401 comes from the security layer with an empty body. Sign-in endpoints use OAuth error / error_description instead.
| 400 | IDB-GNR-40000 | Validation failed on a parameter or the body. |
| 400 | IDB-GNR-40027 | The body isn't valid JSON for this endpoint. |
| 401 | (none) | No token, wrong audience, expired, or a scope missing. Empty body. |
| 404 | IDB-CNF-40400 | No provider with this id, or the id belongs to another provider type. |
| 409 | IDB-CNF-40901 | Name, variant, alias or domain alias already in use (codes 40901 to 40904). |
| 500 | IDB-GNR-50000 | Unexpected failure. Read the configuration back before retrying. |
When a call fails
| Reply | Means | What to change |
|---|---|---|
| The service answers 401 | The token lacks this service's audience, or it expired. | Add the audience to the client's Default audiences (Access admin → Web clients → the client), then get a new token. |
| The service answers 403 and the token has the audience | A scope the operation needs is missing. | Add one of the operation's scopes to the client's Default scopes. Use the scope names your tenant lists under Access admin → Scopes. |
| Token endpoint: 401 invalid_client | Unknown client ID or wrong secret. | Check the client ID and paste the secret again. |
| Token endpoint: 400 unauthorized_client | The client may not use client credentials. | Add the grant type Client credentials to the web client. |
| Token endpoint: 400 invalid_request about an audience | You asked for an audience the client doesn't have. | Add it to Default audiences, or stop asking for it. |
| Token endpoint: 500 right after scopes were added | The client's Default scopes, joined with spaces, are over about 1024 characters. | Move scopes to Additional scopes and request them per call, or split the work over two clients. |
| {"code":"not_found","message":"The requested location was not found"} | That service isn't deployed on this tenant. | Nothing to change in the client. Ask whoever runs the tenant. |
Two kinds of client exist in Access. Service APIs like this one take a web client with the Client credentials grant. Access's own configuration API takes an API client: a web client sent there gets 401 invalid_credentials.