OpenID Connect integration

Overview

Slatehub implements the OpenID Connect Authorization Code flow with PKCE. Tokens are signed with EdDSA (Ed25519). One client per organization.

Discovery

https://slatehub.com/.well-known/openid-configuration

Most OIDC libraries (oidc-client-ts, openid-client, AppAuth, MSAL, etc.) auto-configure from this URL.

Endpoints

GET /authorize
Authorization endpoint — redirect users here.
POST /token
Token endpoint — exchange code or refresh.
GET /userinfo
Returns claims for the bearer token.
POST /revoke
RFC 7009 revocation.
POST /introspect
RFC 7662 introspection.
GET /logout
RP-initiated logout.
GET /.well-known/jwks.json
Public keys for verifying id_tokens.

Scopes

Authorization Code + PKCE flow

Generate a code_verifier and a code_challenge = BASE64URL(SHA256(code_verifier)). Redirect the user to:

https://slatehub.com/authorize
  ?response_type=code
  &client_id=YOUR_CLIENT_ID
  &redirect_uri=https://your-app/callback
  &scope=openid%20profile%20email
  &code_challenge=...
  &code_challenge_method=S256
  &state=...
  &nonce=...

After consent, the user is redirected back with ?code=...&state=.... Exchange the code:

POST https://slatehub.com/token
Authorization: Basic base64(client_id:client_secret)
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code
&code=THE_CODE
&redirect_uri=https://your-app/callback
&code_verifier=THE_VERIFIER

Response:

{
  "access_token": "...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "id_token": "eyJ...",
  "refresh_token": "...",  // only if offline_access requested
  "scope": "openid profile email"
}

UserInfo

GET https://slatehub.com/userinfo
Authorization: Bearer ACCESS_TOKEN

Refresh tokens

Refresh tokens are rotated on use: each call to /token returns a new refresh token and revokes the previous one. Replaying a revoked token kills the entire session chain (RFC 6749 §10.4).

Logout

https://slatehub.com/logout
  ?id_token_hint=...
  &post_logout_redirect_uri=https://your-app/signed-out
  &state=...

The redirect URI must be in your client's post-logout allowlist.