SUPER EARLY WIP — USE AT YOUR OWN RISK■
shoo
GitHubCOMING SOON

How It Works

The sign-in flow, PKCE, callback rules, and server endpoints

The sign-in flow

Your app                     shoo.dev                    Google
  │                            │                           │
  │ 1. startSignIn()           │                           │
  │    create PKCE + state     │                           │
  │ ── redirect /authorize ──▶ │                           │
  │                            │ 2. no Shoo session:       │
  │                            │ ──── redirect ──────────▶ │
  │                            │                           │ 3. user signs in
  │                            │ ◀──── callback ────────── │
  │                            │ 4. first visit from this  │
  │                            │    origin: user confirms  │
  │                            │    (and profile sharing)  │
  │ ◀── redirect ?code&state ─ │                           │
  │                            │                           │
  │ 5. POST /token             │                           │
  │    code + code_verifier ─▶ │ 6. check PKCE, sign JWT   │
  │ ◀── { id_token } ───────── │                           │
  │                            │                           │
  │ 7. save token, return to   │                           │
  │    the starting page       │                           │

If the user already has a Shoo session, step 2 and 3 are skipped. If they already approved your origin, and any requested profile sharing, step 4 is skipped too. The browser still navigates to Shoo and back.

No app registration

Shoo derives your app identity from the callback URL:

client_id = "origin:" + new URL(redirect_uri).origin

For https://myapp.com/auth/callback, this is origin:https://myapp.com. It is also the token audience. See identity and privacy for what this means for previews, localhost, and domain changes.

Origin confirmation

The first time a user signs in to an origin, Shoo shows that origin and asks them to continue. If your app requests profile data, the same page asks to share it. Later sign-ins to an approved origin continue without the page. If the app requests profile data that the user did not approve yet, the page shows again.

If the user disconnects your app at shoo.dev/me, the next sign-in shows the confirmation again.

PKCE

Browser apps cannot keep a secret, so every flow uses PKCE with S256.

  1. The client creates a random code_verifier and sends its SHA-256 hash as code_challenge.
  2. The client keeps the verifier in sessionStorage in the tab that started sign-in.
  3. At /token, the client sends the verifier. Shoo checks it against the challenge.

A stolen code is useless without the verifier. Codes are single use and expire after two minutes.

Callback rules

  • Use a dedicated callback path: /shoo/callback (hosted script default) or /auth/callback (npm default).
  • The callback URL must use https:, or http: on localhost, 127.0.0.1, or ::1.
  • The callback URL must not contain a query string, fragment, or credentials.
  • At /token, the redirect_uri must match the one used at /authorize exactly.
  • The callback page should only finish sign-in. Do not forward its query string or run other logic there.

Tokens

Shoo signs an id_token JWT with ES256. The header has a kid. Public keys are at /.well-known/jwks.json.

The token lasts one hour. It is a bearer token. See tokens and sessions for renewal and revocation, and identity and privacy for claims.

Protocol support

Shoo uses an OAuth 2.0 style authorization code flow with PKCE and returns a signed JWT. It publishes a discovery document at /.well-known/openid-configuration.

Shoo is not a complete OpenID Connect provider. It does not support nonce, userinfo, refresh tokens, or dynamic client registration. Use the Shoo clients or the documented endpoints.

Server endpoints

MethodEndpointUse
GET/authorizeStart sign-in
POST/tokenExchange a code for an id_token. CORS-enabled.
POST/session/checkCheck a token and the app's current approval
GET/.well-known/jwks.jsonPublic signing keys
GET/.well-known/openid-configurationDiscovery document
GET/shoo.jsHosted browser script
GET/meUser account page: connected apps, logout, deletion