Each directory is an OpenID Provider (OpenID Connect Core 1.0, OAuth 2.0) with its own issuer,
https://<alias>.sso.ezgh.app, its own signing keys and its own clients. These endpoints are
defined by the standards, so they aren’t part of the management API reference. They
never accept EZGH Cloud API keys, logins or console sessions.
| Endpoint | Path | Methods |
|---|---|---|
| Discovery | /.well-known/openid-configuration, /.well-known/oauth-authorization-server |
GET |
| JWKS | /jwks |
GET |
| Authorization | /oauth2/authorize |
GET, POST |
| Token | /oauth2/token |
POST |
| Userinfo | /oauth2/userinfo |
GET, POST |
| Introspection | /oauth2/introspect |
POST |
| Revocation | /oauth2/revoke |
POST |
| Logout | /oauth2/logout |
GET, POST |
| Registration | /oauth2/register |
POST |
Discovery, JWKS, token, userinfo, introspection and revocation answer CORS requests from any origin, without credentials, so single-page apps can call them.
Discovery
GET /.well-known/openid-configuration (also at /.well-known/oauth-authorization-server, the
same document) describes the provider:
| Field | Value |
|---|---|
issuer |
https://<alias>.sso.ezgh.app |
response_types_supported |
code |
response_modes_supported |
query |
grant_types_supported |
authorization_code, refresh_token |
code_challenge_methods_supported |
S256 |
scopes_supported |
openid, profile, email, groups, offline_access, mcpcentral:connect |
subject_types_supported |
public |
id_token_signing_alg_values_supported |
RS256, ES256 |
token_endpoint_auth_methods_supported |
client_secret_basic, client_secret_post, private_key_jwt, none |
acr_values_supported |
urn:ezgh:sso:acr:mfa, urn:ezgh:sso:acr:sfa |
authorization_response_iss_parameter_supported |
true |
backchannel_logout_supported, backchannel_logout_session_supported |
true |
request_parameter_supported, request_uri_parameter_supported |
false |
client_id_metadata_document_supported |
true |
JWKS
GET /jwks is the directory’s public signing keys: an RSA key (RS256) and a P-256 key (ES256),
each with a kid. Keys rotate every 90 days; a new key appears 7 days before it signs, and an old
key stays 7 days after it stops. Fetch keys by kid when you see one you don’t have.
Authorization
/oauth2/authorize starts a sign-in. Parameters:
| Parameter | Notes |
|---|---|
response_type |
code only. |
client_id, redirect_uri |
redirect_uri must exactly match one the application registered (a native app’s loopback IP may use any port). |
scope |
Space-separated; include openid for an ID token. Scopes the provider doesn’t support are left out. |
state, nonce |
Returned in the redirect, and in the ID token (nonce). |
code_challenge, code_challenge_method |
PKCE with S256. Required for spa and native applications. |
prompt |
none (fails with login_required instead of showing a page), login (sign in again), select_account (the same as login: a browser has one session), consent (satisfied by the assignment). |
max_age |
Sign in again if the session’s sign-in is older. |
id_token_hint |
If it names another user than the signed-in one, they sign in again. |
response_mode |
query only. |
Not supported: request and request_uri (request_not_supported,
request_uri_not_supported), the claims parameter, other response types and modes.
- Every authorization response, including errors, carries
iss(RFC 9207). Check it. - There’s no consent screen for your applications: assigning a user is your consent.
- Without a session the person signs in at the portal first, under the directory’s policy, and comes back.
- A person who isn’t assigned sees an error page; with
prompt=nonethe app getsaccess_denied. An unknown client or an unregistered redirect URI shows an error page too, and never redirects.
Token
POST /oauth2/token, form-encoded. Grants: authorization_code (with code, redirect_uri,
and code_verifier when PKCE was used) and refresh_token (with refresh_token, and optionally
a narrower scope).
Client authentication, by the application’s tokenEndpointAuthMethod: HTTP Basic with the client
ID and secret (client_secret_basic), client_id and client_secret in the form
(client_secret_post; a secret client may use either), a client_assertion JWT
(private_key_jwt), or client_id alone (public clients).
The answer has access_token, token_type (Bearer), expires_in, scope, id_token (with
openid) and refresh_token (with offline_access). Errors are OAuth’s: invalid_grant for a
used, expired or revoked code or refresh token, or a user who is no longer active or assigned;
invalid_client for failed client authentication.
Userinfo
GET or POST /oauth2/userinfo with Authorization: Bearer <access token> returns the claims
the token’s scopes grant (see Scopes and claims). A token
that isn’t active is 401 with WWW-Authenticate: Bearer error="invalid_token"; a token without
openid is 403.
Introspection
POST /oauth2/introspect (RFC 7662), with token, for confidential (web) applications,
authenticated as at the token endpoint. An application can introspect its own refresh tokens, and
access tokens issued to it or for it: an API registered as its own application, named in the
token’s aud through the issuing application’s accessTokenAudience. The answer is
{ "active": false } for anything revoked, expired, belonging to a suspended or deleted user, or
not the caller’s.
Revocation
POST /oauth2/revoke (RFC 7009), with token, authenticated as at the token endpoint (public
clients send client_id). Revoking a refresh token ends its whole grant; revoking an access token
ends that token.
Logout
/oauth2/logout (OpenID Connect RP-Initiated Logout 1.0) ends the person’s portal session.
| Parameter | Notes |
|---|---|
id_token_hint |
An ID token this directory issued (expired is fine). With it, the session ends at once. Without it, a signed-in person is asked to confirm. |
client_id |
Must be in the hint’s aud, when both are sent. |
post_logout_redirect_uri |
Followed only when the client registered it exactly in postLogoutRedirectUris. |
state |
Returned with the redirect. |
Applications with a backchannelLogoutUri are told through
back-channel logout.
Registration
POST /oauth2/register (RFC 7591) registers a public client for EZGH resource tokens, the way MCP
clients sign in to EZGH products. Clients registered here can’t sign in to your applications and
get no ID tokens. See EZGH apps and MCP clients.