Sign-in and verification

Identity Linking API

Links an identity to its accounts at external identity providers. Each link maps an Identity Store id to an external subject under an IdP alias, so a federated sign-in can find the right user.

https://{tenant-host}/identity-linking/api/v1audience identity-linking4 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

  • Find the identity behind an external account after a federated sign-in.
  • Link an external account to an identity once the journey has proven the user owns both.
  • List or remove the external accounts linked to an identity.

Connect

Base URL
https://{tenant-host}/identity-linking/api/v1
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 identity-linkingchecked live
Default scopes
idl:links:read, idl:links:write, idl:links:delete, idl:links:lookup, one per operation. The documented identity-linking-admin is refused. Some tenants don't define the idl:links:* scopes in Access yet: create them, then add them to the client.from source
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}/identity-linking/api/v1/identities/$IDENTITY_ID/links" \
  -H "Authorization: Bearer $ACCESS_TOKEN"

Operations

Open an operation to see its parameters and code, and send it to your tenant. The token needs the listed scope. Identity and link ids are UUIDs. The service has no configuration endpoints: IdP aliases come from the Identity Broker.

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

The documented scopes are refused

checked live

A token with the identity-linking audience and identity-linking-admin is still refused. The service checks idl:links:read, idl:links:write, idl:links:delete and idl:links:lookup.

Lookup is a POST with the plain external id

from source

Send {"alias":"<idp-alias>","externalId":"<subject>"} to /lookup/links. The external id stays out of the URL. The reply has linkId, identityId, alias and externalIdHashed: use identityId for the user.

Two different 404s

from source

IL-404 means no link for that account. IL-421 means the alias isn't configured (or the broker couldn't be reached). Only IL-404 means a first-time sign-in. Don't create an identity on any 404.

Creating a link checks nothing about the user

from source

The service doesn't check that the identity exists or that the caller owns both accounts. Authenticate the user and verify the external subject in your journey before you link.

Create is not idempotent

from source

A replay answers 409 IL-420. 409 also means the external account is linked to another identity, or the IdP allows one account per identity and this one has one already. Look up the account to see who owns it. Never delete links to force a create through.

Aliases match exactly

from source

Stored aliases are compared as sent: no trimming, no case folding. An unknown alias in the list filter returns an empty list, not an error. Keep the external subject's casing as the IdP sent it.

An empty list proves nothing

from source

GET links for an unknown identity answers 200 with an empty links array, not 404.

Deleting twice answers 404

from source

DELETE checks that the link belongs to the identity in the path, then removes it. A second DELETE, or a link of another identity, answers 404 IL-404.

A 500 doesn't mean nothing happened

from source

The link is saved before events are sent. If sending fails you get 500 IL-510, but the change stays. After a 500, look up or list the links before you retry.

Soft-deleting a user keeps their links

from source

Links are removed when the identity is deleted permanently. A soft delete in Identity Store doesn't touch them.

Errors

Error bodies carry only code and message: no trace id. The number in a code is not the HTTP status. 401 and 403 come from the security layer and have no IL code.

400IL-400Validation: alias or externalId missing.
400IL-401Invalid external id, e.g. blank.
404IL-404No such link, or the link belongs to another identity.
404IL-421Alias not configured, or the broker unavailable with no stored configuration.
409IL-420Link conflict: already linked, linked to another identity, or one account per identity allowed.
500IL-501Identity Broker unavailable.
500IL-510Event publishing failed. The change may already be saved.

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.