This guide is for external developers integrating their application with SigAuth.
It covers:
- how to register an application
- how to implement OIDC Authorization Code + PKCE
- how to validate tokens in backend APIs
- how to map groups/roles for app authorization
- what to verify in development and production
Recommended pattern for most apps:
- Frontend redirects user to IdP
/api/v1/authorize - IdP authenticates user and redirects back with
code - Frontend (or backend BFF) exchanges code at
/api/v1/token - App stores token and calls its own backend APIs
- App backend validates token and enforces authorization
Important:
- IdP handles user authentication.
- Your app backend must still validate tokens and authorize every protected endpoint.
In IdP Admin UI:
- Go to Applications and create a new app
- Choose app type:
spafor browser-only JS appswebfor server-rendered/confidential appsnativefor mobile/desktop appsm2mfor service-to-service
- Configure:
- redirect URIs (exact values)
- allowed scopes (
openid profile emailminimum) - token lifetimes
- refresh token policy (if needed)
- Save
client_id(andclient_secretif applicable) - (Optional but recommended) assign app-level groups for authorization scoping
Use these IdP endpoints:
- Authorization:
GET /api/v1/authorize - Token:
POST /api/v1/token - UserInfo:
GET /api/v1/userinfo - Logout (token revoke):
POST /api/v1/logout - OIDC discovery:
GET /api/v1/.well-known/openid-configuration - JWKS:
GET /api/v1/.well-known/jwks.json - Introspection (confidential clients):
POST /api/v1/introspect
Base URL example:
http://localhost:8000
Generate:
state(random UUID)nonce(random UUID)code_verifier(high-entropy random string)code_challenge = base64url(SHA256(code_verifier))
Redirect to:
GET /api/v1/authorize
?response_type=code
&client_id=<CLIENT_ID>
&redirect_uri=<URL_ENCODED_REDIRECT_URI>
&scope=openid%20profile%20email
&state=<STATE>
&nonce=<NONCE>
&code_challenge=<CODE_CHALLENGE>
&code_challenge_method=S256
At your redirect_uri:
- verify returned
statematches storedstate - extract
code
Send:
POST /api/v1/token
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code
&code=<CODE>
&redirect_uri=<REDIRECT_URI>
&client_id=<CLIENT_ID>
&code_verifier=<CODE_VERIFIER>Response includes id_token (and may include access_token/refresh_token depending on app settings).
Common claims:
ississuersubuser IDaudclient IDexpexpiryemail,nameorg_idrolesgroupsapp_groupsapp_roles
Authorization guidance:
- Prefer
app_rolesfor stable app-specific authorization decisions. - Prefer
app_groupsfor app-specific authorization - Use
groupsfor org-global group membership - Use
rolesfor coarse privileges where appropriate
Your backend must validate bearer tokens:
- Verify JWT signature using IdP public keys (
JWKSor configured PEM) - Verify
issequals your IdP issuer - Verify
audequals your appclient_id - Verify
expandnbf/iatas needed - Reject invalid/expired tokens
Do not rely on frontend-only decoding for security decisions.
Typical mapping logic:
- If token has admin role/group -> app
admin - Else if instructor group -> app
instructor - Else -> app
learner
Keep this mapping:
- centralized in one backend module
- environment-configurable (group names)
- audited when role changes are inferred from token claims
When user signs out:
- App calls IdP
POST /api/v1/logoutwith current bearer token - App clears local token storage/session
- App redirects to login screen
This ensures token revocation is visible in IdP audit logs.
- Use HTTPS for IdP and app URLs
- Keep redirect URI list strict (exact matches only)
- Use PKCE for public clients (SPA/native)
- Keep tokens short-lived
- Enable refresh-token rotation where needed
- Validate
stateandnonce - Store secrets only on server side (never in SPA bundle)
- Implement CSRF controls for cookie-based architectures
- Add rate limiting and lockout handling
- Log auth events for incident traceability
- Login success:
- authorize redirect works
- token exchange returns valid JWT
- Failure paths:
- invalid state rejected
- wrong redirect_uri rejected
- bad code_verifier rejected
- Authorization:
- user in admin app group gets admin UI/API access
- user outside app groups is blocked
- Logout:
- token revoked
- app session cleared
- Expiry:
- expired token rejected by backend
- Audit:
- login/token/logout events visible in IdP audit logs
Share this with developers integrating your IdP:
issuer:http://localhost:8000(or prod URL)client_id:<provided per app>client_secret:<only for confidential clients>redirect_uris:<approved list>scopes:openid profile emaildiscovery:/.well-known/openid-configurationjwks_uri:/.well-known/jwks.json- required token claims for authz:
app_groups,groups,roles - logout endpoint:
/api/v1/logout
Open discovery document:
curl http://localhost:8000/api/v1/.well-known/openid-configurationOpen JWKS:
curl http://localhost:8000/api/v1/.well-known/jwks.jsonIf you want, create a separate per-app onboarding doc using this template with concrete values (client ID, redirect URIs, group names, and role mapping rules) and keep it in your app repository.