Any OIDC stack
Webrizen SSO is a standard OpenID Connect provider, so any language or framework with an OIDC library can use it: Node, Python, PHP, Java, Go, .NET, mobile.
What every integration needs
| Setting | Value |
|---|---|
| Discovery URL | https://accounts.webrizen.com/api/auth/.well-known/openid-configuration |
| Issuer | https://accounts.webrizen.com/api/auth |
| Flow | Authorization code with PKCE (S256) |
| Scopes | openid profile email organization offline_access |
| Client authentication | client_secret_basic (server apps) or none (SPA / mobile) |
| ID token signing | RS256 |
Most libraries only need the discovery URL, client ID, client secret and redirect URI. Everything else is discovered automatically.
Node.js (Express)
import express from "express";
import session from "express-session";
import * as oidc from "openid-client";
const app = express();
app.use(session({ secret: process.env.SESSION_SECRET, resave: false, saveUninitialized: false }));
const config = await oidc.discovery(
new URL(process.env.WEBRIZEN_SSO_ISSUER),
process.env.WEBRIZEN_SSO_CLIENT_ID,
process.env.WEBRIZEN_SSO_CLIENT_SECRET,
);
const redirect_uri = `${process.env.APP_URL}/callback`;
app.get("/login", async (req, res) => {
const code_verifier = oidc.randomPKCECodeVerifier();
const state = oidc.randomState();
req.session.oidc = { code_verifier, state };
const url = oidc.buildAuthorizationUrl(config, {
redirect_uri,
scope: "openid profile email organization",
code_challenge: await oidc.calculatePKCECodeChallenge(code_verifier),
code_challenge_method: "S256",
state,
});
res.redirect(url.href);
});
app.get("/callback", async (req, res) => {
const { code_verifier, state } = req.session.oidc ?? {};
const tokens = await oidc.authorizationCodeGrant(
config,
new URL(req.originalUrl, process.env.APP_URL),
{ pkceCodeVerifier: code_verifier, expectedState: state },
);
const claims = tokens.claims();
req.session.user = { id: claims.sub, email: claims.email, name: claims.name, org: claims.org };
res.redirect("/");
});Python (Django)
Using mozilla-django-oidc:
ISSUER = "https://accounts.webrizen.com/api/auth"
OIDC_RP_CLIENT_ID = env("WEBRIZEN_SSO_CLIENT_ID")
OIDC_RP_CLIENT_SECRET = env("WEBRIZEN_SSO_CLIENT_SECRET")
OIDC_RP_SIGN_ALGO = "RS256"
OIDC_RP_SCOPES = "openid profile email organization"
OIDC_USE_PKCE = True
OIDC_OP_AUTHORIZATION_ENDPOINT = f"{ISSUER}/oauth2/authorize"
OIDC_OP_TOKEN_ENDPOINT = f"{ISSUER}/oauth2/token"
OIDC_OP_USER_ENDPOINT = f"{ISSUER}/oauth2/userinfo"
OIDC_OP_JWKS_ENDPOINT = f"{ISSUER}/jwks"Organization data arrives in the userinfo response under org. Read it in a custom
OIDCAuthenticationBackend.update_user / create_user to map roles onto your models.
PHP, Java, Go, .NET
Pick your framework's maintained OIDC client (for example Spring Security OAuth2 Client,
coreos/go-oidc, Microsoft.AspNetCore.Authentication.OpenIdConnect, or a Laravel/Symfony
OIDC package), then configure it with the values in the table above.
Doing it by hand
If you must, the flow is three HTTP requests:
# 1. Send the browser to:
https://accounts.webrizen.com/api/auth/oauth2/authorize?response_type=code
&client_id=CLIENT_ID&redirect_uri=REDIRECT_URI
&scope=openid%20profile%20email%20organization
&state=RANDOM&code_challenge=S256_CHALLENGE&code_challenge_method=S256
# 2. Exchange the returned code (server-side):
curl -u CLIENT_ID:CLIENT_SECRET https://accounts.webrizen.com/api/auth/oauth2/token \
-d grant_type=authorization_code -d code=CODE \
-d redirect_uri=REDIRECT_URI -d code_verifier=VERIFIER
# 3. Fetch the user:
curl -H "Authorization: Bearer ACCESS_TOKEN" \
https://accounts.webrizen.com/api/auth/oauth2/userinfoVerify the signature against the JWKS, and check iss, aud (your client ID), exp and the
nonce if you sent one. Libraries do this for you, which is the main reason to use one.
Single-page and mobile apps
Register the app as Single-page app or Mobile / desktop. These get no client secret and
rely on PKCE. Use a library such as oidc-client-ts (browser) or AppAuth (iOS/Android).
Keep tokens in memory where possible, and prefer a backend-for-frontend when your app has a
server.