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
main.go
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}) }

Authorization Code + PKCE

handlers.go
// 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)

m2m.go
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

introspect.go
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
auth.js
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

routes.js
// 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

routes.js
// 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)

m2m.js
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
auth.py
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)

routes.py
@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)

m2m.py
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
verify.py
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/