Docs: add a browser SPA integration example #31

Closed
opened 2026-05-25 14:20:20 +00:00 by navicore · 1 comment
Owner

Background

The README's Quick Start walks through a server-side OIDC integration (Forgejo-style: anz client add ... [--secret], server validates tokens). Since anz now supports browser SPAs (cors_allowed_origins, PKCE-only public clients), there's a second integration mode that has no example anywhere in the docs.

Encountered

The navinote PWA was the first browser SPA consumer. Several non-obvious things had to be figured out from source/spec:

  • Register a public client (no --secret) so PKCE is enforced.
  • Set cors_allowed_origins = ["https://your-app.example.com"] in anz.toml.
  • Browser flow: fetch /.well-known/openid-configuration cross-origin (CORS-bound), navigate to /authorize (not a fetch, so no CORS), POST /token cross-origin with code_verifier (CORS-bound), refresh tokens cross-origin.
  • Audience to validate at the resource server: realm URL, not client_id (see #30).

Proposed

A short section in the README — "Integrating a browser SPA" — covering:

  1. Register a public PKCE client.
  2. Add the SPA's origin to cors_allowed_origins.
  3. ~10-line JS/TS sketch of the PKCE auth-code flow (generate verifier, redirect, callback, token exchange, refresh).
  4. Note that the resource server validating ATs should accept the realm URL as aud.

Doesn't have to be exhaustive — pointer to a working reference (e.g. navinote's pwa/src/lib/auth.js) is fine.

Why now

We don't know whether another SPA will integrate soon. If the answer is "no", this is low priority. If the answer is "expected within the year", the README section pays for itself.

## Background The README's Quick Start walks through a server-side OIDC integration (Forgejo-style: `anz client add ... [--secret]`, server validates tokens). Since anz now supports browser SPAs (`cors_allowed_origins`, PKCE-only public clients), there's a second integration mode that has no example anywhere in the docs. ## Encountered The navinote PWA was the first browser SPA consumer. Several non-obvious things had to be figured out from source/spec: - Register a public client (no `--secret`) so PKCE is enforced. - Set `cors_allowed_origins = ["https://your-app.example.com"]` in `anz.toml`. - Browser flow: fetch `/.well-known/openid-configuration` cross-origin (CORS-bound), navigate to `/authorize` (not a fetch, so no CORS), `POST /token` cross-origin with `code_verifier` (CORS-bound), refresh tokens cross-origin. - Audience to validate at the resource server: realm URL, not `client_id` (see #30). ## Proposed A short section in the README — "Integrating a browser SPA" — covering: 1. Register a public PKCE client. 2. Add the SPA's origin to `cors_allowed_origins`. 3. ~10-line JS/TS sketch of the PKCE auth-code flow (generate verifier, redirect, callback, token exchange, refresh). 4. Note that the resource server validating ATs should accept the realm URL as `aud`. Doesn't have to be exhaustive — pointer to a working reference (e.g. navinote's `pwa/src/lib/auth.js`) is fine. ## Why now We don't know whether another SPA will integrate soon. If the answer is "no", this is low priority. If the answer is "expected within the year", the README section pays for itself.
Author
Owner

#32

https://git.navicore.tech/navicore/anz/pulls/32
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
navicore/anz#31
No description provided.