Code Examples
Go · Node.js · Python
Ready-to-run snippets for the most common OIDC/OAuth 2.1 flows using each language's
idiomatic library. Replace id.clavex.eu/acme with your own issuer URL.
Setup
go get golang.org/x/oauth2 github.com/coreos/go-oidc/v3/oidc
package main
import ( "context" "crypto/rand" "encoding/base64" "net/http" "github.com/coreos/go-oidc/v3/oidc" "golang.org/x/oauth2" ) const ( issuer = "https://id.clavex.eu/acme" clientID = "clavex_01925..." redirectURL = "http://localhost:3000/callback" ) var ( provider *oidc.Provider oauth2Cfg oauth2.Config verifier *oidc.IDTokenVerifier ) func init() { ctx := context.Background() provider, _ = oidc.NewProvider(ctx, issuer) oauth2Cfg = oauth2.Config{ ClientID: clientID, Endpoint: provider.Endpoint(), RedirectURL: redirectURL, Scopes: []string{oidc.ScopeOpenID, "email", "profile"}, } verifier = provider.Verifier(&oidc.Config{ClientID: clientID}) }
import ( "context" "crypto/rand" "encoding/base64" "net/http" "github.com/coreos/go-oidc/v3/oidc" "golang.org/x/oauth2" ) const ( issuer = "https://id.clavex.eu/acme" clientID = "clavex_01925..." redirectURL = "http://localhost:3000/callback" ) var ( provider *oidc.Provider oauth2Cfg oauth2.Config verifier *oidc.IDTokenVerifier ) func init() { ctx := context.Background() provider, _ = oidc.NewProvider(ctx, issuer) oauth2Cfg = oauth2.Config{ ClientID: clientID, Endpoint: provider.Endpoint(), RedirectURL: redirectURL, Scopes: []string{oidc.ScopeOpenID, "email", "profile"}, } verifier = provider.Verifier(&oidc.Config{ClientID: clientID}) }
Authorization Code + PKCE
// handleLogin — initiates the auth flow
func handleLogin(w http.ResponseWriter, r *http.Request) {
state := randomString(16)
http.SetCookie(w, &http.Cookie{Name: "state", Value: state, HttpOnly: true, Secure: true})
// PKCE — generate verifier + S256 challenge
pkce := oauth2.GenerateVerifier()
http.SetCookie(w, &http.Cookie{Name: "pkce", Value: pkce, HttpOnly: true, Secure: true})
url := oauth2Cfg.AuthCodeURL(state, oauth2.S256ChallengeOption(pkce))
http.Redirect(w, r, url, http.StatusFound)
}
// handleCallback — exchanges code for tokens
func handleCallback(w http.ResponseWriter, r *http.Request) {
state, _ := r.Cookie("state")
if r.URL.Query().Get("state") != state.Value {
http.Error(w, "state mismatch", http.StatusBadRequest); return
}
pkce, _ := r.Cookie("pkce")
token, err := oauth2Cfg.Exchange(r.Context(), r.URL.Query().Get("code"),
oauth2.VerifierOption(pkce.Value))
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError); return
}
rawIDToken, _ := token.Extra("id_token").(string)
idToken, err := verifier.Verify(r.Context(), rawIDToken)
if err != nil {
http.Error(w, "invalid id_token", http.StatusUnauthorized); return
}
var claims struct {
Sub string `json:"sub"`
Email string `json:"email"`
Name string `json:"name"`
}
idToken.Claims(&claims)
// claims.Sub, claims.Email, claims.Name are now populated
}
func randomString(n int) string {
b := make([]byte, n)
rand.Read(b)
return base64.URLEncoding.EncodeToString(b)[:n]
}
Client Credentials (M2M)
func getM2MToken(ctx context.Context) (string, error) {
cfg := &oauth2.Config{
ClientID: "clavex_01925...",
ClientSecret: "cs_...",
Endpoint: provider.Endpoint(),
Scopes: []string{"api:read", "api:write"},
}
token, err := cfg.Token(ctx)
if err != nil {
return "", err
}
return token.AccessToken, nil
}
Token Introspection
type IntrospectResult struct {
Active bool `json:"active"`
Sub string `json:"sub"`
Scope string `json:"scope"`
ExpiresAt int64 `json:"exp"`
}
func introspect(ctx context.Context, accessToken string) (*IntrospectResult, error) {
data := url.Values{
"token": {accessToken},
"client_id": {clientID},
"client_secret": {"cs_..."},
}
resp, err := http.PostForm(issuer+"/introspect", data)
if err != nil { return nil, err }
defer resp.Body.Close()
var result IntrospectResult
json.NewDecoder(resp.Body).Decode(&result)
return &result, nil
}
Setup
npm install openid-client express express-session
import { Issuer, generators } from 'openid-client';
const ISSUER = 'https://id.clavex.eu/acme';
const CLIENT_ID = 'clavex_01925...';
const REDIRECT_URI = 'http://localhost:3000/callback';
// Discover OIDC configuration from .well-known endpoint
const issuer = await Issuer.discover(ISSUER);
const client = new issuer.Client({
client_id: CLIENT_ID,
redirect_uris: [REDIRECT_URI],
response_types: ['code'],
token_endpoint_auth_method: 'none', // public client (PKCE)
});
Authorization Code + PKCE
// GET /login — start the auth flow
app.get('/login', (req, res) => {
const state = generators.state();
const codeVerifier = generators.codeVerifier();
const codeChallenge = generators.codeChallenge(codeVerifier);
// Store in session for the callback
req.session.state = state;
req.session.codeVerifier = codeVerifier;
const url = client.authorizationUrl({
scope: 'openid email profile',
state,
code_challenge: codeChallenge,
code_challenge_method: 'S256',
});
res.redirect(url);
});
// GET /callback — exchange code for tokens
app.get('/callback', async (req, res) => {
const params = client.callbackParams(req);
const tokens = await client.callback(REDIRECT_URI, params, {
state: req.session.state,
code_verifier: req.session.codeVerifier,
});
// Verify and decode ID token
const claims = tokens.claims();
console.log(claims.sub, claims.email, claims.name);
// Store access_token for later API calls
req.session.accessToken = tokens.access_token;
res.redirect('/');
});
UserInfo & Token Refresh
// Fetch userinfo from the IdP
const userinfo = await client.userinfo(req.session.accessToken);
console.log(userinfo); // { sub, email, email_verified, name, ... }
// Refresh an expired access token
const refreshed = await client.refresh(req.session.refreshToken);
req.session.accessToken = refreshed.access_token;
req.session.refreshToken = refreshed.refresh_token;
Client Credentials (M2M)
const m2mClient = new issuer.Client({
client_id: 'clavex_01925...',
client_secret: 'cs_...',
token_endpoint_auth_method: 'client_secret_post',
});
const tokens = await m2mClient.grant({
grant_type: 'client_credentials',
scope: 'api:read api:write',
});
console.log(tokens.access_token);
Setup
pip install authlib requests flask
from authlib.integrations.flask_client import OAuth
from flask import Flask, redirect, url_for, session
app = Flask(__name__)
oauth = OAuth(app)
clavex = oauth.register(
'clavex',
client_id='clavex_01925...',
# client_secret='cs_...' ← omit for public clients (PKCE only)
server_metadata_url='https://id.clavex.eu/acme/.well-known/openid-configuration',
client_kwargs={
'scope': 'openid email profile',
'code_challenge_method': 'S256', # PKCE
},
)
Authorization Code + PKCE (Flask)
@app.route('/login')
def login():
redirect_uri = url_for('auth_callback', _external=True)
return clavex.authorize_redirect(redirect_uri)
@app.route('/callback')
def auth_callback():
token = clavex.authorize_access_token()
# token contains access_token, id_token, refresh_token
userinfo = token.get('userinfo')
# or fetch separately:
# userinfo = clavex.userinfo(token=token)
session['user'] = {
'sub': userinfo['sub'],
'email': userinfo['email'],
'name': userinfo.get('name'),
}
return redirect('/')
Client Credentials (M2M)
import requests
TOKEN_ENDPOINT = 'https://id.clavex.eu/acme/token'
resp = requests.post(TOKEN_ENDPOINT, data={
'grant_type': 'client_credentials',
'client_id': 'clavex_01925...',
'client_secret': 'cs_...',
'scope': 'api:read api:write',
})
token_data = resp.json()
access_token = token_data['access_token']
# Use the token
api_resp = requests.get(
'https://api.example.com/resource',
headers={'Authorization': f'Bearer {access_token}'},
)
Verify ID Token (PyJWT)
pip install PyJWT[crypto] cryptography
import jwt, requests
ISSUER = 'https://id.clavex.eu/acme'
JWKS_URI = f'{ISSUER}/.well-known/jwks.json'
CLIENT_ID = 'clavex_01925...'
# Fetch public keys
jwks = requests.get(JWKS_URI).json()
jwks_client = jwt.PyJWKClient(JWKS_URI)
def verify_id_token(id_token: str) -> dict:
signing_key = jwks_client.get_signing_key_from_jwt(id_token)
payload = jwt.decode(
id_token,
signing_key.key,
algorithms=['RS256', 'ES256'],
audience=CLIENT_ID,
issuer=ISSUER,
)
return payload # {'sub': '...', 'email': '...', 'exp': ...}
SDK & Webhook Libraries
Clavex ships first-party client SDKs and webhook validation libraries:
Go SDK
Webhook signature verification, event type constants, structured payload parsing.
sdk/go/
Node.js Webhooks
NPM package for verifying Clavex webhook HMAC-SHA256 signatures.
sdk/webhooks-js/
Python Webhooks
PyPI package for verifying Clavex webhook HMAC-SHA256 signatures.
sdk/webhooks-py/