Single Sign-On

OpenID Connect

OpenID Connect (OIDC) is a thin identity layer on top of OAuth 2.0. It’s the recommended protocol for new integrations — lighter than SAML, native to modern web and mobile stacks, and easier to debug.

i

Hygrade acts as the OpenID Provider (OP) for first-party integrations. For federation into Hygrade — where your IdP authenticates your employees — use SAML 2.0. OIDC federation for IdP-into-Hygrade is on the roadmap.

Discovery

Hygrade publishes a standard OpenID discovery document at a well-known URL. Most client libraries can configure themselves from this one endpoint.

Issuer
PRODhttps://order.hygradebusiness.com
TESThttps://test.hygradebusiness.com
Discovery document
PRODhttps://order.hygradebusiness.com/.well-known/openid-configuration
TESThttps://test.hygradebusiness.com/.well-known/openid-configuration
JWKS
PRODhttps://order.hygradebusiness.com/oauth/jwks.json
TESThttps://test.hygradebusiness.com/oauth/jwks.json
GET /.well-known/openid-configuration
{
  "issuer": "https://order.hygradebusiness.com",
  "authorization_endpoint": "https://order.hygradebusiness.com/oauth/authorize",
  "token_endpoint": "https://order.hygradebusiness.com/oauth/token",
  "userinfo_endpoint": "https://order.hygradebusiness.com/oauth/userinfo",
  "jwks_uri": "https://order.hygradebusiness.com/oauth/jwks.json",
  "revocation_endpoint": "https://order.hygradebusiness.com/oauth/revoke",
  "introspection_endpoint": "https://order.hygradebusiness.com/oauth/introspect",
  "end_session_endpoint": "https://order.hygradebusiness.com/oauth/logout",
  "response_types_supported": ["code", "id_token", "code id_token"],
  "grant_types_supported": ["authorization_code", "refresh_token", "client_credentials"],
  "subject_types_supported": ["public"],
  "id_token_signing_alg_values_supported": ["RS256"],
  "scopes_supported": [
    "openid", "profile", "email",
    "orders:read", "orders:write", "catalog:read",
    "users:read", "users:write"
  ],
  "claims_supported": [
    "sub", "iss", "aud", "exp", "iat", "auth_time",
    "email", "email_verified",
    "given_name", "family_name", "name",
    "cust_id", "login", "groups", "cost_center"
  ],
  "code_challenge_methods_supported": ["S256"],
  "token_endpoint_auth_methods_supported": ["client_secret_basic", "client_secret_post", "private_key_jwt"]
}

Sign-in flow

Hygrade supports the Authorization Code flow with PKCE. The request is identical to the OAuth flow, with the addition of the openid scope and (optionally) nonce.

Authorization request
GET https://order.hygradebusiness.com/oauth/authorize
    ?response_type=code
    &client_id=hg_live_8f3c92e4a1b04e79
    &redirect_uri=https%3A%2F%2Fapp.acmecorp.com%2Fcallback
    &scope=openid%20profile%20email
    &state=9a1dcf4b
    &nonce=f7d23c0b9e
    &code_challenge=dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk
    &code_challenge_method=S256

The token response includes an id_token alongside the access token:

200 OK
{
  "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVC...",
  "id_token":     "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVC...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "hgr_a4f2e8c1d9b34...",
  "scope": "openid profile email"
}

ID token

The ID token is a JWT signed with RS256. Always verify the signature against the JWKS and enforce the following:

Decoded ID token
{
  "iss": "https://order.hygradebusiness.com",
  "sub": "shopper:acme001:jdoe",
  "aud": "hg_live_8f3c92e4a1b04e79",
  "exp": 1760731200,
  "iat": 1760727600,
  "auth_time": 1760727598,
  "nonce": "f7d23c0b9e",

  "email": "jane.doe@acmecorp.com",
  "email_verified": true,
  "given_name": "Jane",
  "family_name": "Doe",
  "name": "Jane Doe",

  "cust_id": "ACME001",
  "login": "jdoe",
  "groups": ["buyer", "approver"],
  "cost_center": "CC-4420"
}

Claims

ClaimScopeDescription
subopenidStable, opaque identifier for the shopper. Format: shopper:<custId>:<login>.
emailemailPrimary email address.
email_verifiedemailBoolean; always true for SSO-authenticated users.
given_nameprofileFirst name.
family_nameprofileLast name.
nameprofileFull display name.
cust_idprofileHygrade customer account code.
loginprofileHygrade login identifier.
groupsprofileRole memberships. Array of strings.
cost_centerprofileDefault cost center code, if assigned.

UserInfo endpoint

Clients that need user attributes without decoding the ID token can call the UserInfo endpoint with the access token. Requires the openid scope.

GET /oauth/userinfo
curl https://order.hygradebusiness.com/oauth/userinfo \
  -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsI..."
200 OK
{
  "sub": "shopper:acme001:jdoe",
  "email": "jane.doe@acmecorp.com",
  "email_verified": true,
  "given_name": "Jane",
  "family_name": "Doe",
  "name": "Jane Doe",
  "cust_id": "ACME001",
  "login": "jdoe",
  "groups": ["buyer", "approver"],
  "cost_center": "CC-4420"
}

Logout (end session)

The end_session_endpoint terminates the Hygrade session. Clients should also clear their own session.

GET /oauth/logout
GET https://order.hygradebusiness.com/oauth/logout
    ?id_token_hint=eyJhbGciOiJSUzI1NiIs...
    &post_logout_redirect_uri=https%3A%2F%2Fapp.acmecorp.com%2Fsigned-out
    &state=9a1dcf4b

Tested client libraries

Any OIDC-conformant library works. These are the ones we regularly see in integrations and exercise in our test suite:


Related: for the OAuth primitives themselves (token formats, scopes, error handling) see the OAuth 2.0 reference.