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 operations
Last checked against a live tenant: 28 October 2026checked live called on a tenantfrom source read in the service codenot confirmed not confirmed

When 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/token with grant_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 use broker. Neither has been seen working on a tenant yet. Test one without calling the broker: add audience=identity-broker to the token request. A 400 invalid_request means the client doesn't have it.from source
Default scopes
broker:get for reads, broker:post for writes. The service maps them to the roles role_broker_read and role_broker_write that 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-configuration needs no token. Issuer is https://{tenant-host}/broker; the only grant is authorization_code; clients authenticate with private_key_jwt or client_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 source

The 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 source

The 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 source

It 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 source

PUT 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 source

Provider 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 source

Accept 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 source

A second delete of the same provider is still 204. Confirm with the list instead of trusting the status.

Metadata fetches are restricted

from source

The *-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 source

A 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.

400IDB-GNR-40000Validation failed on a parameter or the body.
400IDB-GNR-40027The body isn't valid JSON for this endpoint.
401(none)No token, wrong audience, expired, or a scope missing. Empty body.
404IDB-CNF-40400No provider with this id, or the id belongs to another provider type.
409IDB-CNF-40901Name, variant, alias or domain alias already in use (codes 40901 to 40904).
500IDB-GNR-50000Unexpected failure. Read the configuration back before retrying.

When a call fails

ReplyMeansWhat to change
The service answers 401The 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 audienceA 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_clientUnknown client ID or wrong secret.Check the client ID and paste the secret again.
Token endpoint: 400 unauthorized_clientThe client may not use client credentials.Add the grant type Client credentials to the web client.
Token endpoint: 400 invalid_request about an audienceYou 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 addedThe 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.