A self-contained HTML test console for the whole stack, built as a 4-step wizard: choose an auth method → configure a credential → log in → inspect the session. Three methods are available — form login, OAuth2 (four stub providers), and a stateless bearer/JWT leg — each demonstrating a distinct, independently-composable authn mechanism in go-security.
Open http://localhost:8080.

What’s demonstrated

  • Form login — JSON body POST /login, CSRF token supplied automatically from the XSRF-TOKEN cookie, session cookie, fixation protection
  • RegistrationPOST /api/register adds a new user to the in-memory store at runtime (always ROLE_USER — self-service privilege selection at registration would be a privilege-escalation bug in a real app)
  • OAuth2 login — all four providers (Google, GitHub, Facebook, Zalo) via a local httptest stub
  • Bearer token (JWT) — a stateless resource-server leg composed alongside the session chain (see Source highlights below): mint a short-lived HS256 JWT for a seeded account, then call GET /api/bearer/whoami with Authorization: Bearer <token>. No cookie, no CSRF, no session — and session-only endpoints correctly 401 for a bearer-only caller, demonstrating the two mechanisms don’t interfere
  • CSRF — double-submit cookie strategy (XSRF-TOKEN cookie ↔ X-CSRF-Token header); the browser reads the cookie and echoes it on unsafe requests
  • Authorization/api/admin requires ROLE_ADMIN, /api/user requires any authenticated user, /api/whoami is public, /api/bearer/whoami requires a valid bearer token
  • Security headers — inspect response headers with DevTools

How the OAuth2 stub works

The playground starts a single *httptest.Server that handles three endpoints, shared by all four providers:
Each provider’s ClientRegistration points all of its OAuth2 endpoints at this stub, so the result is a fully functional PKCE authorization-code flow that works offline, with no developer-console registration required. Every OAuth2 login resolves to the same subject (oauth2-user-42) and gets a synthesized ROLE_USER.

Source highlights

combinedUserService

OAuth2 principals (subjects) are not in the static user store. A combinedUserService wraps the static service and synthesizes an authn.User for unknown subjects:
This is the recommended pattern for apps that support both form login and OAuth2 social login.

Handler assembly

The Login endpoint and every unsafe request are protected by the double-submit CSRF repository; the OAuth2 callbacks use GET (a safe method) and are exempt by design — the session-bound state parameter is their CSRF defense.

Bearer token leg

The bearer/JWT method is a second, independent authn leg composed alongside the session chain above rather than merged into it — first-class composition of a bearer leg into securityhttp’s own chain is a documented future gap (see securityhttp/README.md), so the playground demonstrates the pattern examples/resource uses standalone: a route mounted with resource.RequireBearer directly, outside securityhttp’s authorize step.
The outer authz.Routes() rule for that path is PermitAll() — it just lets the request through without requiring a session; RequireBearer does the real authentication (and its own 401 challenge) once the request reaches the app mux. POST /api/bearer/token mints a demo HS256 JWT for a seeded account, standing in for an IdP’s token endpoint.

Log panel

The UI shows a real-time log of HTTP interactions as you use the playground. Each entry shows the method, path, status code, and the response body.

Credentials

The same two seeded accounts drive both form login and bearer-token minting: OAuth2 logins always resolve to ROLE_USER via the stub userinfo endpoint.