Early WIP — Use at your own risk

Documentation

Introduction

Shoo is a free, open-source OAuth provider that lets you add secure authentication to any application in minutes. No signup required, no API keys, no backend needed.

Point your redirect URI to shooauth.com and go. Shoo handles the OAuth flow, identity tokens, and session management. You get verified user identities via JWT.

Quick Start

Add Shoo to any app with just 2 lines of code. Works with React, Vue, vanilla JS, or any framework.

1<!-- 1. Add the script -->
2<script src="https://shooauth.com/shoo.js"></script>
3
4<!-- 2. Add a login link -->
5<a href="https://shooauth.com/sign-in?redirect_uri=https://yourapp.com/callback">
6 Login
7</a>

SDK Installation

For React apps, use our official SDK for a smoother integration with hooks and automatic session management.

1# Install the Shoo React SDK
2bun add @shoojs/react @shoojs/auth
3
4# Or use the CDN (works with any framework)
5<script src="https://cdn.jsdelivr.net/npm/@shoojs/auth"></script>

OAuth with Shoo

Shoo provides OAuth/OpenID Connect authentication. Users are redirected to shooauth.com to complete sign-in, then returned to your application with a verified identity token.

1// Sign in with Shoo (redirects to shooauth.com)
2await signIn({ requestPii: true }); // Request name/email
3
4// Or minimal sign-in (just userId)
5await signIn();

Session Management

Shoo handles sessions automatically. Tokens are stored in localStorage and refreshed as needed. The React SDK provides automatic session monitoring.

1const { sessionState, checkSession } = useShooAuth();
2
3// Session states: "unknown" | "active" | "login_required"
4if (sessionState === "login_required") {
5 // Redirect to sign in
6}
7
8// Explicitly check session validity
9const result = await checkSession();
10// { status: "active" } | { status: "login_required", reason: "expired" | "revoked" | "invalid_token" }

OAuth Callback

Create a callback page to handle the OAuth redirect. Works in any framework.

callback.tsx
1// Next.js, React, or any framework
2import { useShooAuth } from "@shoojs/react";
3
4export default function Callback() {
5 const { handleCallback } = useShooAuth();
6
7 useEffect(() => {
8 handleCallback({ redirectAfter: false })
9 .then((token) => {
10 if (token?.id_token) {
11 // Token contains: pairwise_sub, email, name (if requested)
12 window.location.href = "/dashboard";
13 }
14 });
15 }, []);
16
17 return <div>Signing in...</div>;
18}

useShooAuth Hook

The primary hook for interacting with Shoo Auth. Provides authentication state, sign-in methods, and user identity information.

1interface UseShooAuthReturn {
2 identity: ShooIdentity; // { userId: string | null; token?: string; expiresIn?: number; }
3 claims: IdentityClaims | null; // Decoded JWT claims (pairwise_sub, email, name, etc.)
4 loading: boolean;
5 sessionState: "unknown" | "active" | "login_required";
6 error: string | null;
7 // Actions
8 signIn: (options?: StartSignInOptions) => Promise<void>;
9 handleCallback: (options?: HandleCallbackOptions) => Promise<TokenResponse | null>;
10 checkSession: () => Promise<SessionCheckResult>;
11 refreshIdentity: () => void;
12 clearIdentity: () => void;
13 // Client reference
14 authClient: ShooAuthClient | null;
15}

Configuration Options

1useShooAuth({
2 shooBaseUrl: "https://shooauth.com", // Shoo OAuth server
3 callbackPath: "/auth/callback", // OAuth callback route
4 autoHandleCallback: true, // Auto-process callback params
5 autoSessionMonitor: true, // Enable background session checks
6 sessionMonitorIntervalMs: 60000, // Check interval (default: 60s)
7});

signIn

Initiates the OAuth authentication flow by redirecting to Shoo. After successful authentication, the user is redirected back to your callback path.

1interface StartSignInOptions {
2 requestPii?: boolean; // Request personal info (name, email)
3 returnTo?: string; // Path to redirect after sign-in
4 redirectUri?: string; // Override the OAuth redirect URI
5 clientId?: string; // Override the OAuth client ID
6 shooBaseUrl?: string; // Override the Shoo server URL
7}

OAuth Callback Handler

Handle the OAuth callback after the user returns from Shoo. Exchange the authorization code for tokens and establish the session.

The handleCallback method is available from the React hook. For direct client usage, use finishSignIn from the auth client.

auth/callback/page.tsx
1"use client";
2
3import { useEffect } from "react";
4import { useShooAuth } from "@shoojs/react";
5
6export default function AuthCallback() {
7 const { handleCallback } = useShooAuth();
8
9 useEffect(() => {
10 handleCallback({ redirectAfter: false })
11 .then((token) => {
12 if (token) {
13 // Verify token with your backend
14 window.location.href = "/dashboard";
15 }
16 });
17 }, [handleCallback]);
18
19 return <div>Completing sign-in...</div>;
20}

Clear Identity / Sign Out

Clear the local session. Shoo is stateless — there's no server-side session to invalidate.

1const { clearIdentity } = useShooAuth();
2
3// Clear local session
4clearIdentity();

Token Verification

Verify Shoo ID tokens server-side using JWKS. The tokens are JWTs signed by Shoo's keys and contain the user's pairwise_sub claim (unique per app).

api/verify/route.ts
1import { createRemoteJWKSet, jwtVerify } from "jose";
2
3const jwks = createRemoteJWKSet(
4 new URL("/.well-known/jwks.json", "https://shooauth.com")
5);
6
7// In your API route
8export async function POST(request: Request) {
9 const { idToken } = await request.json();
10
11 const { payload } = await jwtVerify(idToken, jwks, {
12 issuer: "https://shooauth.com",
13 audience: "origin:https://yourdomain.com",
14 });
15
16 // payload.pairwise_sub contains the unique user ID
17 return Response.json({ userId: payload.pairwise_sub });
18}

Environment Setup

No environment variables required for basic usage. Just point your redirect URI to shooauth.com. For the React SDK, you can optionally configure the base URL.

1// Optional: Configure SDK (defaults shown)
2useShooAuth({
3 shooBaseUrl: "https://shooauth.com",
4 callbackPath: "/auth/callback",
5});

Security

Shoo implements OAuth 2.0 with PKCE and OpenID Connect:

  • Pairwise user IDs (privacy-preserving, different per app)
  • JWKS-based JWT verification with RS256 signatures
  • Origin-bound tokens (audience validation prevents cross-site replay)
  • PKCE flow for OAuth authorization code exchange
  • 30-day token expiration
  • No backend required — Shoo handles all OAuth server-side