文档以英文发布。

DocumentationGet started

Your first verified sign-in

Sandbox only

The runnable path: authorize, approve as a test identity, exchange, read.

Before you start

You need three things: a sandbox application, at least one test identity on it (see Test identities), and your own developer account signed in, because *you* are the one who will approve the consent screen on the test identity's behalf.

1. Send the person to authorize

With no prompt, an adequate session and unchanged permissions continue automatically. Explicit prompt=login, consent, select_account and none are supported, together with max_age and login_hint. See How the flow works.

Query parameters

response_typecode
The only response type offered.
client_id
The sandbox client id, exactly as the quickstart endpoint returned it.
redirect_uri
Must match a registered redirect URI character for character.
scope
Space-separated scope codes. Every one must exist in the catalogue and be inside the application's allowedClaimScopes.
state
Cryptographic randomness you will check on the way back.
nonce
Bound into the ID token. Check it on the way back.
code_challenge
The S256 challenge for your verifier.
code_challenge_methodS256
The only method the discovery document offers.
purpose
One sentence, at most 200 characters, shown to the person. If you send nothing they see Sign in to <your application name>.
display
Only the value popup is forwarded; anything else is dropped.
The URL you build
GET /v1/oauth/authorize
  ?response_type=code
  &client_id=<your sandbox client id>
  &redirect_uri=https%3A%2F%2Flocalhost%3A8443%2Fcallback
  &scope=openid%20profile%20email%20age_over_18
  &state=<32+ bytes of randomness>
  &nonce=<random>
  &code_challenge=<base64url(sha256(verifier))>
  &code_challenge_method=S256
  &purpose=Confirm%20you%20are%20over%2018%20before%20checkout

2. Approve as a test identity

On the consent screen, a member of the sandbox application's team can choose Sign in as a test identity. It is a control on the hosted screen, not something you call from your own code: it needs your signed-in developer account plus a fresh sign-in confirmation for exactly this authorization request.

Approving is one decision covering everything the screen listed. There are no per-claim toggles. The alternative is Cancel, which sends error=access_denied to your redirect URI.

3. Exchange the code

POST /v1/oauth/token. Client authentication is client_secret_basic, client_secret_post, or none for a public client — all three are advertised in the discovery document. The code verifier is always required if you sent a challenge.

Token exchange
curl -s -X POST "$UNIFYID_API/v1/oauth/token" \
  -u "$CLIENT_ID:$CLIENT_SECRET" \
  -H "content-type: application/x-www-form-urlencoded" \
  -d grant_type=authorization_code \
  -d code="$CODE" \
  -d redirect_uri="https://localhost:8443/callback" \
  -d code_verifier="$CODE_VERIFIER"

What the token endpoint returns

access_token
Bearer it at /v1/userinfo.
token_typeBearer
Always.
expires_in
Seconds. Read it; do not hard-code a lifetime.
id_token
Present when openid was granted. RS256, verified against the JWKS. Besides the standard claims it carries identity_verified, consent_id (bind your own sessions to this consent), first_sign_in (true on the sign-in that created the connection) and connected_at (ISO 8601, when the person first connected your application).
scope
Space-separated — what was actually granted, which can be narrower than what you asked for.

4. Read what you were given

Use the verified issuer/client/sub to reuse the application account, even after reconnection. Bind your own session to the verified ID token's consent_id and handle signed consent.revoked webhooks to end those sessions. Never create duplicate users from first_sign_in. See Revocation and webhooks for the atomic storage and sign-out pattern.

GET /v1/userinfo returns a flat map of claim values, not a wrapped envelope and not a metadata structure.

Userinfo
curl -s "$UNIFYID_API/v1/userinfo" \
  -H "authorization: Bearer $ACCESS_TOKEN"

An unauthenticated or expired call answers 401 with a recorded shape:

401 from /v1/userinfo (recorded)
{
  "error": {
    "code": "invalid_token",
    "message": "A valid OAuth access token is required.",
    "requestId": "7015cb0d-ac1a-427c-9b4f-0dacb1a2235e"
  }
}

What this does not do

  • A claim you asked for can come back absent. Absent is not false and not null — the key simply is not there. Handling the callback explains why that is unavoidable and what to do about it.
  • This sign-in starts a 30-day clock. It satisfies the sandbox_sign_in go-live check, and that check goes stale: if 30 days pass with no sandbox sign-in, it fails again.
  • A test identity never reaches the disclosure ledger. Signing in as one writes no disclosure event, though it does count as a token issuance for the checklist.

Verified against API commit 234dba22 on 2026-10-18. The routes, scopes, checklist, events and limits on these pages are read from that export, not typed.