跳到主要内容

OpenID Connect

aknAPI acts as an OpenID Connect provider for registered relying parties, and as a claims source for the upstream identity provider that fronts akn ID.

PropertyValue
Issuerhttps://api.akn.me.uk
FlowAuthorisation code
Signing algorithmRS256
Client authenticationclient_secret_post and client_secret_basic
PKCES256 and plain
Scopes advertisedopenid, email, profile
Subject typepublic
Refresh tokensNot available
Dynamic client registrationNot available
End-session endpointNot available

Clients are registered by the site operator against a fixed redirect URI allowlist. A client may also carry a required project, in which case only people holding that grant, the * grant, or the admin role receive a code.

Endpoints

MethodPathCredential
GET/.well-known/openid-configurationNone
GET/auth/oidc/.well-known/openid-configurationNone
GET/auth/oidc/jwksNone
GET/auth/oidc/authorizeNone. The browser is redirected to sign in
GET/auth/oidc/callbackSession cookie. Called by the sign-in page
POST/auth/oidc/tokenClient credentials
GET/auth/oidc/userinfoAccess token

Discovery is served at both paths with identical content. A client that asserts the issuer matches the discovery host should use the root path.

GET /auth/oidc/authorize

ParameterRequiredDetail
response_typeYesMust be code
client_idYesRegistered client
redirect_uriYesMust match the client's allowlist exactly
stateNoReturned on the redirect back
nonceNoCopied into the ID token
code_challengeNoPKCE challenge
code_challenge_methodNoS256 or plain

A valid request answers 302 to https://id.akn.me.uk to sign in, and the browser returns to /auth/oidc/callback.

ConditionStatusBody
response_type is not code400{"error":"unsupported_response_type"}
Client not registered401{"error":"invalid_client"}
redirect_uri missing400{"error":"invalid_request","error_description":"redirect_uri required"}
redirect_uri not on the allowlist400{"error":"invalid_request","error_description":"redirect_uri not registered"}

Errors are returned to the caller, never delivered to the requested redirect_uri. A relying party that only inspects its callback sees nothing at all when a request is rejected here.

The pending request expires five minutes after /auth/oidc/authorize is called. A sign-in that takes longer returns Login session expired. Please try again. as plain text with status 400.

GET /auth/oidc/callback

Called with the state issued at /auth/oidc/authorize once the session cookie is set. Issues the authorisation code and answers 302 to the relying party's redirect_uri with code, and state when one was supplied.

ConditionResult
No valid session302 back to the sign-in page
Signed in without the client's required project403 with an HTML page naming the missing project
Signed in and permitted302 to redirect_uri

An unauthorised person is not redirected to the relying party. The refusal is shown on this page.

POST /auth/oidc/token

Accepts application/x-www-form-urlencoded or JSON.

FieldRequiredDetail
grant_typeYesMust be authorization_code
codeYesCode from the callback redirect
redirect_uriYesMust equal the value used at /auth/oidc/authorize
client_idConditionalOmit when using Basic authorisation
client_secretConditionalOmit when using Basic authorisation
code_verifierConditionalRequired when a challenge was sent and the client has a registered allowlist

Response, 200.

{
"access_token": "…",
"token_type": "Bearer",
"expires_in": 3600,
"id_token": "…"
}
ConditionStatusBody
Client unknown, or the secret does not match401{"error":"invalid_client"}
grant_type is not authorization_code400{"error":"unsupported_grant_type"}
Code unknown, already redeemed, or older than two minutes400{"error":"invalid_grant"}
redirect_uri differs from the authorise request400{"error":"invalid_grant"}
Code redeemed by a different client400{"error":"invalid_grant"}
PKCE verifier missing400{"error":"invalid_grant","error_description":"code_verifier required"}
PKCE verifier does not match400{"error":"invalid_grant","error_description":"PKCE verification failed"}
Signing failed500{"error":"server_error"}

ID token claims

ClaimDetail
isshttps://api.akn.me.uk
audThe client id
subSign-in identity of the person
emailAddress on the session, or on the person record
email_verifiedTrue only when the address was proved
phone_numberPresent only when a number is held
phone_number_verifiedPresent alongside phone_number
nameDisplay name, falling back to the address
akn_roleuser or admin
akn_projectsArray of project grants
noncePresent when supplied at the authorise request

email_verified reflects the real state. Do not key an account on email alone when the claim is false.

GET /auth/oidc/userinfo

Requires Authorization: Bearer <access_token>.

{
"sub": "…",
"email": "[email protected]",
"email_verified": true,
"name": "…",
"akn_role": "user",
"akn_projects": ["startpage"]
}
ConditionStatusBody
No bearer header401{"error":"invalid_token"} with WWW-Authenticate: Bearer
Token unknown or older than one hour401{"error":"invalid_token"}

Lifetimes

ItemLifetimeReuse
Pending authorise request5 minutesSingle use
Authorisation code2 minutesSingle use
Access token1 hourReusable until expiry
ID token1 hourNot accepted back by this service

Pending requests, codes and access tokens are held for the life of the process. A restart invalidates every one of them: sign-ins in flight fail, and calls to /auth/oidc/userinfo with a previously valid token answer 401. ID tokens already issued remain valid until they expire, since they are verified against the published key.

Claims target

POST /auth/zitadel/claims supplies akn ID authorisation to the upstream identity provider while it mints a token. It is not a general-purpose endpoint.

PropertyDetail
CredentialZITADEL-Signature: t=<unix>,v1=<hex> over the exact request body
Replay window300 seconds either side of the timestamp
Refused403 with {"error":"invalid_signature"}

Response, 200.

{
"append_claims": [ { "key": "urn:akn:role", "value": "user" } ],
"append_log_claims": ["akn: matched person … on email"]
}
ClaimDetail
email, email_verifiedAppended when the caller proved a verified address
phone_number, phone_number_verifiedAppended when a verified number was proved
urn:akn:person_idThe person the identifiers resolved to
urn:akn:statuspending, approved or rejected
urn:akn:roleuser or admin
urn:akn:projectsArray of project grants

A signed call that resolves no person still answers 200, with the urn:akn: claims absent. A relying party must treat a missing urn:akn:projects as no access rather than as an error, because a lookup failure produces the same result.

  • Authentication covers the session that /auth/oidc/callback reads.
  • Errors covers the difference between OAuth error codes and the rest of the API.
  • Diagnostics covers failed relying party integrations.