This documentation guides you through integrating CZL Connect into your app.
Have a question? Leave a message on the forumOIDC Integration Guide
CZL Connect provides OpenID Connect on top of the OAuth 2.0 Authorization Code flow.
It supports Discovery, JWKS, id_token, PKCE, and multiple client authentication methods.
Protocol Scope
OIDC adds identity authentication on top of OAuth 2.0.
For your app, the main differences are:
scopemust includeopenid- The token response includes an
id_token - You can fetch the configuration from the Discovery endpoint
- You can fetch the signing public keys from the JWKS endpoint
Client Authentication Methods
| Client type | Recommended authentication method |
|---|---|
| Server-side web app | secret |
| Desktop app | none + PKCE |
| Mobile app | none + PKCE |
| SPA / browser frontend | none + PKCE |
A secret client in the CZL Connect admin console supports both standard OIDC/OAuth 2.0 parameter-passing methods: client_secret_basic and client_secret_post.
When the client authentication method is none, the authorization code exchange must use PKCE.
Discovery
Endpoint
| Endpoint | URL |
|---|---|
| Discovery | https://connect.czl.net/.well-known/openid-configuration |
Example
GET https://connect.czl.net/.well-known/openid-configuration
Response
{
"issuer": "https://connect.czl.net",
"authorization_endpoint": "https://connect.czl.net/oidc/authorize",
"token_endpoint": "https://connect.czl.net/api/oidc/token",
"userinfo_endpoint": "https://connect.czl.net/api/oidc/userinfo",
"introspection_endpoint": "https://connect.czl.net/api/oidc/introspect",
"jwks_uri": "https://connect.czl.net/api/oidc/jwks",
"response_types_supported": ["code", "id_token", "code id_token"],
"subject_types_supported": ["public"],
"id_token_signing_alg_values_supported": ["RS256"],
"scopes_supported": ["openid", "profile", "email"],
"grant_types_supported": ["authorization_code", "refresh_token"],
"response_modes_supported": ["query", "fragment"],
"code_challenge_methods_supported": ["S256"],
"token_endpoint_auth_methods_supported": ["client_secret_basic", "client_secret_post", "none"]
}
Authorization Request
Parameters
| Parameter | Required | Description |
|---|---|---|
response_type | Yes | Always code |
client_id | Yes | The client ID |
redirect_uri | Yes | The redirect URI |
scope | Yes | Must include openid |
state | No | State parameter; always send it |
nonce | No | Recommended; protects against replay attacks |
prompt | No | none requests silent authentication and behaves as described in "Silent Authentication" in the OAuth 2.0 guide |
code_challenge | Required with PKCE | The PKCE challenge |
code_challenge_method | Required with PKCE | Always S256 |
With prompt=none, if authorization cannot complete silently, CZL Connect redirects back to redirect_uri with error (login_required, consent_required, interaction_required, and so on) and state, and shows no interactive page. Start the request with a top-level full-page navigation, not an iframe (the session cookie is SameSite=Lax and is not sent inside an iframe). The supported values are listed in prompt_values_supported in Discovery.
Traditional Client
https://connect.czl.net/oidc/authorize?
response_type=code
&client_id=YOUR_CLIENT_ID
&redirect_uri=YOUR_REDIRECT_URI
&scope=openid profile email
&state=RANDOM_STATE_VALUE
&nonce=RANDOM_NONCE_VALUE
Public Client + PKCE
https://connect.czl.net/oidc/authorize?
response_type=code
&client_id=YOUR_CLIENT_ID
&redirect_uri=YOUR_REDIRECT_URI
&scope=openid profile email
&state=RANDOM_STATE_VALUE
&nonce=RANDOM_NONCE_VALUE
&code_challenge=YOUR_CODE_CHALLENGE
&code_challenge_method=S256
Token Request
Exchange an Authorization Code for Tokens
secret client: client_secret_post
POST https://connect.czl.net/api/oidc/token
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code
&code=AUTHORIZATION_CODE
&client_id=YOUR_CLIENT_ID
&client_secret=YOUR_CLIENT_SECRET
&redirect_uri=YOUR_REDIRECT_URI
secret client: client_secret_basic
POST https://connect.czl.net/api/oidc/token
Content-Type: application/x-www-form-urlencoded
Authorization: Basic BASE64(YOUR_CLIENT_ID:YOUR_CLIENT_SECRET)
grant_type=authorization_code
&code=AUTHORIZATION_CODE
&redirect_uri=YOUR_REDIRECT_URI
none + PKCE
POST https://connect.czl.net/api/oidc/token
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code
&code=AUTHORIZATION_CODE
&client_id=YOUR_CLIENT_ID
&redirect_uri=YOUR_REDIRECT_URI
&code_verifier=YOUR_CODE_VERIFIER
Response
{
"access_token": "ACCESS_TOKEN",
"id_token": "ID_TOKEN_JWT",
"token_type": "bearer",
"expires_in": 3600,
"refresh_token": "REFRESH_TOKEN",
"scope": "openid profile email"
}
ID Token
Example
{
"jti": "UNIQUE_TOKEN_ID",
"iss": "https://connect.czl.net",
"sub": "1",
"aud": "YOUR_CLIENT_ID",
"exp": 1640995200,
"iat": 1640991600,
"nbf": 1640991600,
"nonce": "RANDOM_NONCE_VALUE",
"at_hash": "ACCESS_TOKEN_HASH",
"name": "zhangsan",
"email": "[email protected]",
"email_verified": true,
"picture": "https://example.com/avatar.png",
"groups": ["t0", "t1", "t2", "t3", "t4", "t5", "viewer", "admin"]
}
Fields
| Field | Description |
|---|---|
iss | Issuer |
sub | Unique user identifier |
aud | Intended client |
exp | Expiration time |
iat | Issued-at time |
nbf | Not-before time |
nonce | The nonce from the client's request |
at_hash | Access token hash |
groups | The user's groups as an array of strings, including the groups inherited from the user's level |
UserInfo
Request
GET https://connect.czl.net/api/oidc/userinfo
Authorization: Bearer ACCESS_TOKEN
Refresh Token
secret client: client_secret_post
POST https://connect.czl.net/api/oidc/token
Content-Type: application/x-www-form-urlencoded
grant_type=refresh_token
&refresh_token=REFRESH_TOKEN
&client_id=YOUR_CLIENT_ID
&client_secret=YOUR_CLIENT_SECRET
secret client: client_secret_basic
POST https://connect.czl.net/api/oidc/token
Content-Type: application/x-www-form-urlencoded
Authorization: Basic BASE64(YOUR_CLIENT_ID:YOUR_CLIENT_SECRET)
grant_type=refresh_token
&refresh_token=REFRESH_TOKEN
none
POST https://connect.czl.net/api/oidc/token
Content-Type: application/x-www-form-urlencoded
grant_type=refresh_token
&refresh_token=REFRESH_TOKEN
&client_id=YOUR_CLIENT_ID
Migrating to PKCE
To migrate from the traditional client_secret mode to PKCE, change the following:
- Change the client authentication method to
none - Add
code_challengeandcode_challenge_method=S256to the authorization request - Remove
client_secretfrom the token request - Add
code_verifierto the token request
The scope, Discovery URL, JWKS URL, and UserInfo URL stay the same.
Validation Requirements
Your app must validate the following:
- The
id_tokensignature issaudexpnonce
Security Requirements
scopemust includeopenid- Use
client_secretonly in server-side apps that can keep secrets confidential - Public clients must use PKCE
- Only
S256is currently supported - Desktop apps, mobile apps, and browser frontends must not embed
client_secret