Any OIDC client
Integrate Authio with any OpenID Connect library: discovery, the authorization code flow with PKCE, SPAs and native apps, token validation, refresh and sign-out.
Every realm is a standard OpenID Connect provider, so any certified OIDC or OAuth 2.0 library works without an Authio SDK. Give the library the realm’s issuer, a client ID and, for a confidential client, its secret; it reads everything else from discovery. This page shows the requests on the wire, so you know what the library does and can check it with curl.
Discovery
The issuer is https://authio.api.hyperio.tech/realms/{realm}. Its discovery document lists the endpoints, the scopes and grants the realm’s clients use, and the supported algorithms. It is served at the OpenID Connect address and at both forms of RFC 8414, with CORS open to any origin.
curl https://authio.api.hyperio.tech/realms/acme/.well-known/openid-configuration| Discovery field | Path under the issuer |
|---|---|
authorization_endpoint | /protocol/openid-connect/auth |
token_endpoint | /protocol/openid-connect/token |
userinfo_endpoint | /protocol/openid-connect/userinfo |
jwks_uri | /protocol/openid-connect/certs |
introspection_endpoint | /protocol/openid-connect/introspect |
revocation_endpoint | /protocol/openid-connect/revoke |
end_session_endpoint | /protocol/openid-connect/logout |
device_authorization_endpoint | /protocol/openid-connect/device/auth |
Configure your library with the issuer rather than individual endpoints. The full list, with every parameter, is in OIDC endpoints.
Register the client
| Setting | What to choose |
|---|---|
| Client authentication | Confidential for anything with a server that can keep a secret. Public (method none) for SPAs, mobile and desktop apps. |
| Token endpoint authentication method | client_secret_basic (the default) or client_secret_post. The token endpoint accepts only the registered method. |
| Grant types | authorization_code, plus refresh_token if you renew sessions. |
| PKCE | Required by default. Public clients must keep it on and allow S256. |
| Redirect URIs | Every address the sign-in may come back to, compared in full. Only http and https, without wildcards or fragments. |
| Post-logout redirect URIs | Where sign-out may send people back. Empty accepts the redirect URIs. |
| Scopes | Every scope the app will ask for, such as openid profile email offline_access. |
Authorization code with PKCE
Create a verifier and its challenge
The verifier is a random string the app keeps; the challenge is its SHA-256 hash in base64url. Also create a random
stateandnoncefor this sign-in.TerminalBashCODE_VERIFIER=$(openssl rand -hex 32) CODE_CHALLENGE=$(printf '%s' "$CODE_VERIFIER" | openssl dgst -sha256 -binary | openssl base64 -A | tr '+/' '-_' | tr -d '=')Send the browser to the authorization endpoint
Authorization requestPlain texthttps://authio.api.hyperio.tech/realms/acme/protocol/openid-connect/auth ?response_type=code &client_id=acme-web &redirect_uri=https%3A%2F%2Fapp.example.com%2Fcallback &scope=openid%20profile%20email%20offline_access &state=STATE &nonce=NONCE &code_challenge=CODE_CHALLENGE &code_challenge_method=S256Optional parameters:
prompt(none,login,select_account,consent),max_age,login_hint,ui_locales,id_token_hint,organizationandresource— one resource server identifier, to get an access token for that API.display=popupwithresponse_mode=web_messageruns the sign-in in a popup.Receive the code
After the hosted login, the browser comes back with
code,stateandiss(RFC 9207). Check thatstateis the one you sent andissis the realm’s issuer. The code is single-use and expires after 30 seconds, so exchange it right away. A refusal comes back witherrorinstead, also withstateandiss.CallbackPlain texthttps://app.example.com/callback?code=AUTHORIZATION_CODE&state=STATE&iss=https%3A%2F%2Fauthio.api.hyperio.tech%2Frealms%2FacmeExchange the code for tokens
Confidential clientBashcurl -X POST https://authio.api.hyperio.tech/realms/acme/protocol/openid-connect/token \ -u 'acme-web:YOUR_CLIENT_SECRET' \ -d grant_type=authorization_code \ -d code=AUTHORIZATION_CODE \ --data-urlencode redirect_uri=https://app.example.com/callback \ -d code_verifier=$CODE_VERIFIERResponseJSON{ "access_token": "eyJhbGciOiJSUzI1NiIs...", "token_type": "Bearer", "expires_in": 1800, "refresh_token": "eyJhbGciOiJSUzI1NiIs...", "refresh_expires_in": 3600, "id_token": "eyJhbGciOiJSUzI1NiIs...", "scope": "openid profile email offline_access" }Validate the ID token as OpenID Connect Core asks: signature,
iss,audequal to your client ID,exp, andnonceequal to the one you sent. Presenting the same code twice revokes the session it was issued in.
SPAs, mobile and native apps
Apps that run on the user’s device cannot keep a secret, so they use a public client with PKCE and S256. Use a library that does the flow above for you — an OpenID-certified one for your platform.
- SPAs redirect back to an
httpspage of the app. The discovery document, the JWKS and the token endpoint answer any origin, so the code can be redeemed from the browser. To keep tokens out of the browser altogether, put a Backend-for-Frontend in front of the SPA. - Desktop apps and CLIs listen on the loopback interface. Register
http://127.0.0.1/callbackand turn on Loopback on any port: Authio then accepts any port on127.0.0.1,[::1]andlocalhost(RFC 8252). - Mobile apps come back through an
httpslink the app claims (universal links or app links). Redirect URIs must behttporhttps, so custom URI schemes are not accepted. - Devices without a browser, such as TVs, use the device flow instead.
Validate access tokens
An API checks each access token locally against the realm’s keys; a valid token needs no call to Authio. Use your platform’s JWT library with these rules:
| Check | Rule |
|---|---|
| Signature | A key from jwks_uri, matched by kid. Accept asymmetric algorithms only: RS, PS and ES 256/384/512. Never none. |
| Issuer | iss equals the realm’s issuer exactly. |
| Audience | aud is your API’s resource server identifier. Without resource, tokens carry the client’s audience, Authio by default. |
| Lifetime | exp in the future, nbf in the past, with a small clock skew. |
| Token type | The typ claim is Bearer. ID and refresh tokens are signed by the same keys and must be refused. |
| Permissions | scope holds the granted scopes; roles are in the *_resource_access claims when the roles scope was granted. |
A JWT stays valid until it expires, even after the session ends. To catch revocations and sign-outs sooner, or to accept opaque or encrypted tokens, ask the introspection endpoint (RFC 7662) as a confidential client allowed to introspect the API’s tokens. It always answers 200, with active: false and nothing else for any token that is not valid.
curl -X POST https://authio.api.hyperio.tech/realms/acme/protocol/openid-connect/introspect \
-u 'orders-api:YOUR_CLIENT_SECRET' \
-d token=ACCESS_TOKEN \
-d token_type_hint=access_tokenRefresh tokens
A refresh token is issued only when offline_access is granted. Present it with the same client authentication as the code exchange:
curl -X POST https://authio.api.hyperio.tech/realms/acme/protocol/openid-connect/token \
-u 'acme-web:YOUR_CLIENT_SECRET' \
-d grant_type=refresh_token \
-d refresh_token=REFRESH_TOKEN- Refresh tokens rotate by default: store the new
refresh_tokenfrom every response. - Within the reuse window (10 seconds by default), a repeated request gets the same new refresh token. A spent token presented after that ends the whole session and is reported as possible theft.
- The renewal keeps
auth_time,amrand the originalresource. It returns anid_tokenonly if the client turns on ID Token on Refresh. - A refusal is
invalid_grant: sign the person in again.
UserInfo
The UserInfo endpoint returns the person’s current claims, read fresh on every call, as far as the token’s scopes allow. It needs a token granted the openid scope. It answers JSON unless the client asked for a signed or encrypted JWT: see Signed and encrypted UserInfo.
curl https://authio.api.hyperio.tech/realms/acme/protocol/openid-connect/userinfo \
-H 'Authorization: Bearer ACCESS_TOKEN'Sign out
To end the person’s session, send the browser to the end-session endpoint with the ID token you received. Only a valid id_token_hint ends the session — an expired one is accepted. Without it, Authio shows a confirmation screen instead.
https://authio.api.hyperio.tech/realms/acme/protocol/openid-connect/logout
?id_token_hint=ID_TOKEN
&post_logout_redirect_uri=https%3A%2F%2Fapp.example.com%2F
&state=STATEpost_logout_redirect_uri is followed only if it is registered on the client, compared like a redirect URI; state comes back unchanged. To drop tokens without signing the person out of the realm’s other apps, revoke the refresh token instead (RFC 7009): this ends the client’s session and keeps single sign-on.
curl -X POST https://authio.api.hyperio.tech/realms/acme/protocol/openid-connect/revoke \
-u 'acme-web:YOUR_CLIENT_SECRET' \
-d token=REFRESH_TOKEN \
-d token_type_hint=refresh_tokenApps that must learn when a session ends elsewhere — an administrator, a suspension, another tab — can register a back-channel or front-channel logout URI. See Sessions and SSO.