OpenID Connect endpoints
Every protocol address of a realm — discovery, JWKS, authorization, token, UserInfo, introspection, revocation, end session and device authorization — with parameters and examples.
Each realm is an OpenID Provider of its own. Its issuer is {base}/realms/{realm} and every endpoint sits under it, so a client configured with the issuer finds the rest through discovery. The examples on this page use the realm acme on the shared platform:
https://authio.api.hyperio.tech/realms/acmeOn a Dedicated environment, replace the host with your environment’s API address. A token issued by one realm is never accepted by another.
Endpoints at a glance
| Endpoint | Method | Path under the issuer | Rate limit |
|---|---|---|---|
| Discovery | GET | /.well-known/openid-configuration | None |
| JWKS | GET | /protocol/openid-connect/certs | None |
| Authorization | GET | /protocol/openid-connect/auth | 300 per minute |
| Token | POST | /protocol/openid-connect/token | 50 per minute |
| UserInfo | GET, POST | /protocol/openid-connect/userinfo | 300 per minute |
| Introspection | POST | /protocol/openid-connect/introspect | 50 per minute |
| Revocation | POST | /protocol/openid-connect/revoke | 50 per minute |
| End session | GET | /protocol/openid-connect/logout | 50 per minute |
| Device authorization | POST | /protocol/openid-connect/device/auth | 50 per minute |
Limits count each caller per realm. A refused request gets 429 with a Retry-After header. Responses that carry credentials — token, introspection, revocation, UserInfo, device authorization — are sent with Cache-Control: no-store.
Discovery
The provider metadata is served at three addresses, so a client finds it whichever convention it follows: OpenID Connect Discovery appends the suffix to the issuer, while RFC 8414 inserts it after the host, the form MCP clients try first.
curl https://authio.api.hyperio.tech/realms/acme/.well-known/openid-configuration
curl https://authio.api.hyperio.tech/.well-known/oauth-authorization-server/realms/acme
curl https://authio.api.hyperio.tech/.well-known/openid-configuration/realms/acmeThe document describes the realm as it is configured, not a generic catalogue:
| Field | Value |
|---|---|
scopes_supported, grant_types_supported | Everything the realm’s clients allow, together. |
code_challenge_methods_supported | The PKCE methods the realm’s clients allow; S256 when none is set. |
response_types_supported | code |
response_modes_supported | query, web_message |
display_values_supported | page, popup |
token_endpoint_auth_methods_supported | client_secret_basic, client_secret_post, none — the same for introspection and revocation. |
id_token_signing_alg_values_supported | RS256, RS384, RS512, PS256, PS384, PS512, ES256, ES384, ES512 |
subject_types_supported | public |
acr_values_supported | 1, 2, 3 |
prompt_values_supported | none, login, select_account, consent |
authorization_response_iss_parameter_supported | true |
frontchannel_logout_supported, backchannel_logout_supported | true, with their _session_supported counterparts. |
client_id_metadata_document_supported | true only when the realm accepts clients that register from a metadata document URL. |
There is no dynamic client registration endpoint, and signed request objects (request, request_uri) are not supported. Discovery answers 404 for a realm that does not exist.
JWKS
The public keys that verify the realm’s tokens, as a JWK Set (RFC 7517). Every token names the key that signed it in its kid header. Keys rotate on a schedule, so cache the set and fetch it again when a token names a kid you do not have.
curl https://authio.api.hyperio.tech/realms/acme/protocol/openid-connect/certsAuthorization endpoint
Starts a sign-in with the authorization code flow. The browser is sent here, the hosted login runs the client’s sign-in steps, and the browser comes back to your redirect_uri with a code.
| Parameter | Required | Notes |
|---|---|---|
client_id | Yes | The client ID, such as acme-web. |
redirect_uri | Yes | Must equal one of the client’s registered redirect URIs: scheme, host, port, path and query. |
response_type | Yes | code, the only one supported. |
scope | Yes | Space-separated. Must include openid unless the client is plain OAuth 2.0, and every scope must be enabled on the client. Add offline_access for a refresh token. |
code_challenge, code_challenge_method | When PKCE is on — the default | S256 or plain, as the client allows. A challenge without a method is refused. |
state | Recommended | Returned unchanged with the response. |
nonce | Recommended | Copied into the ID token. |
prompt | No | none, login, select_account or consent. none cannot be combined with another value. |
max_age | No | Seconds since the last sign-in after which the person signs in again. |
id_token_hint, login_hint | No | An ID token this realm issued to the client; an identifier to prefill on the sign-in screen. |
acr_values | No | 1 single factor, 2 multi-factor, 3 phishing-resistant. A preference: it never refuses the sign-in. |
resource | No | One resource server URI (RFC 8707), which becomes the access token’s audience. |
organization | No | The alias of the organization the sign-in is for. |
ui_locales | No | Preferred languages for the screens, most preferred first. |
response_mode, display | No | query (the default) and page; web_message and popup for a sign-in in a popup window. |
https://authio.api.hyperio.tech/realms/acme/protocol/openid-connect/auth
?client_id=acme-web
&response_type=code
&redirect_uri=https%3A%2F%2Fapp.acme.com%2Fcallback
&scope=openid%20profile%20email%20offline_access
&state=af0ifjsldkj
&nonce=n-0S6_WzA2Mj
&code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM
&code_challenge_method=S256The response carries code, state and iss (RFC 9207). The code is valid for 30 seconds and only once: presenting it again revokes the session it was issued in. Until the redirect_uri is proven, errors are shown on an error page rather than redirected; after that they come back to the redirect_uri with error, error_description, state and iss.
Token endpoint
Exchanges a grant for tokens. The body is application/x-www-form-urlencoded. A confidential client authenticates with HTTP Basic (client_secret_basic, the default) or with client_id and client_secret in the body (client_secret_post) — only the method registered on the client is accepted, and Basic wins when both are sent. A public client sends only its client_id and relies on PKCE. Private key JWT client authentication is not supported.
Supported grants
| Grant | grant_type | Refresh token |
|---|---|---|
| Authorization code | authorization_code | With offline_access |
| Refresh token | refresh_token | Rotated on each use by default |
| Client credentials | client_credentials | No |
| Password | password | Only when the client allows it |
| Device code | urn:ietf:params:oauth:grant-type:device_code | With offline_access |
| Token exchange | urn:ietf:params:oauth:grant-type:token-exchange | No |
| Personal access token | personal_access_token | No |
Each grant must be enabled on the client. An unknown grant gets unsupported_grant_type; a known one the client has not enabled gets unauthorized_client.
curl https://authio.api.hyperio.tech/realms/acme/protocol/openid-connect/token \
-u "acme-web:$CLIENT_SECRET" \
-d grant_type=authorization_code \
-d code="$CODE" \
--data-urlencode redirect_uri=https://app.acme.com/callback \
-d code_verifier="$CODE_VERIFIER"| Response field | When |
|---|---|
access_token, token_type, expires_in | Always. token_type is Bearer. |
id_token | When a person signs in with the openid scope; on refresh, when the client is set to reissue it. |
refresh_token, refresh_expires_in | When a refresh token is issued. |
scope | The scopes granted. |
issued_token_type | Token exchange only. |
Device authorization
Starts the device flow (RFC 8628) for input-constrained devices. The client authenticates as at the token endpoint and must have the device code grant enabled.
curl https://authio.api.hyperio.tech/realms/acme/protocol/openid-connect/device/auth \
-d client_id=acme-cli \
--data-urlencode "scope=openid profile offline_access"| Response field | Value |
|---|---|
device_code | What the device polls the token endpoint with. |
user_code | Eight characters shown as XXXX-XXXX, for the person to type. |
verification_uri | {issuer}/device, where the person types the code. |
verification_uri_complete | The same page with the code filled in, for a QR code. |
expires_in | Seconds until the codes expire: 10 minutes. |
interval | Seconds to wait between polls: 5. |
While the person decides, polling answers authorization_pending; polling too fast answers slow_down; after 10 minutes, expired_token; a denied request, access_denied. See Device flow.
UserInfo
Returns the current claims of the person behind an access token: always sub, plus the claims the token’s profile, email and phone scopes allow, read fresh on every call. A token without openid gets 403 with insufficient_scope; an invalid one, 401 with invalid_token, both with a WWW-Authenticate header.
curl https://authio.api.hyperio.tech/realms/acme/protocol/openid-connect/userinfo \
-H "Authorization: Bearer $ACCESS_TOKEN"Introspection
Tells an API whether a token is still active (RFC 7662), including revocation, ended sessions and suspended users that a signature check alone cannot see. The caller authenticates as a client. The answer is always 200: {"active": false} for any token that is not valid, with no reason given.
curl https://authio.api.hyperio.tech/realms/acme/protocol/openid-connect/introspect \
-u "acme-web:$CLIENT_SECRET" \
-d token="$ACCESS_TOKEN" \
-d token_type_hint=access_tokenAn active token returns active, scope, client_id, username, token_type, exp, iat, nbf, sub, aud, iss and jti, plus authorization claims such as roles, acr, amr, sid and the organization. With token_type_hint=api_key the client asks about one of its consumers’ API keys instead: an active key returns sub (the consumer), client_id, scope, consumer_name, credential_id, credential_type and consumer_resource_access.
Revocation
Invalidates a token you no longer need (RFC 7009), typically at sign-out. The caller authenticates as a client, and every well-formed request gets 200, even for an unknown or expired token. Revoking ends the session behind the token, which also invalidates its refresh tokens; the person stays signed in to the realm’s other applications.
curl https://authio.api.hyperio.tech/realms/acme/protocol/openid-connect/revoke \
-u "acme-web:$CLIENT_SECRET" \
-d token="$REFRESH_TOKEN" \
-d token_type_hint=refresh_tokenEnd session
Signs the person out of the realm (RP-Initiated Logout). Send the browser here with:
| Parameter | Notes |
|---|---|
id_token_hint | An ID token this realm issued; an expired one is accepted. Without a valid hint nothing is ended and the person sees a confirmation screen instead. |
client_id | The client signing out; read from the hint when omitted. |
post_logout_redirect_uri | Where to go afterwards. Followed only when registered on the client, compared exactly like a redirect URI. |
state | Returned unchanged. |
ui_locales | Preferred languages for the screens. |
https://authio.api.hyperio.tech/realms/acme/protocol/openid-connect/logout
?id_token_hint=ID_TOKEN
&post_logout_redirect_uri=https%3A%2F%2Fapp.acme.com%2F
&state=af0ifjsldkjClients that registered a back-channel or front-channel logout URI are told whenever one of their sessions ends — at sign-out, but also when an administrator revokes it or the user is suspended. See Sessions and SSO.
Other addresses under a realm
| Address | What it is for |
|---|---|
/realms/{realm}/device | The page where people type a device code — the verification_uri. |
/realms/{realm}/broker/{alias}/callback | The redirect URI to register at an external identity provider. Accepts GET and POST. |
/realms/{realm}/connections/callback | The redirect URI to register at a connected-account provider. |
/realms/{realm}/clients/{client}/webauthn/... | Passkey ceremonies used by the hosted pages. |
Errors
Protocol endpoints answer errors with the fields of RFC 6749 §5.2, plus Authio’s own error_code to match a report against the logs:
{
"error": "invalid_client",
"error_description": "Invalid client credentials. The provided client_secret is not valid.",
"error_code": "InvalidClientCredentials"
}Every error value and the codes behind it are listed in Error codes.