Authentication
Shokupan provides built-in OAuth2 authentication with support for GitHub, Google, Microsoft, Apple, Auth0, Okta, and custom providers.
Quick Start
Section titled “Quick Start”bun add shokupanimport { Shokupan, AuthPlugin } from 'shokupan';
const app = new Shokupan();
const auth = new AuthPlugin({ jwtSecret: process.env.JWT_SECRET!, jwtExpiration: '7d',
cookieOptions: { httpOnly: true, secure: true, sameSite: 'lax' },
github: { clientId: process.env.GITHUB_CLIENT_ID!, clientSecret: process.env.GITHUB_CLIENT_SECRET!, redirectUri: 'http://localhost:3000/auth/github/callback' }});
// Mount auth routes at /authapp.mount('/auth', auth);
// Protect routesapp.get('/protected', auth.middleware(), (ctx) => { return { user: ctx.state.user };});
app.listen();Supported Providers
Section titled “Supported Providers”GitHub
Section titled “GitHub”const auth = new AuthPlugin({ jwtSecret: 'your-secret', github: { clientId: process.env.GITHUB_CLIENT_ID!, clientSecret: process.env.GITHUB_CLIENT_SECRET!, redirectUri: 'http://localhost:3000/auth/github/callback' }});google: { clientId: process.env.GOOGLE_CLIENT_ID!, clientSecret: process.env.GOOGLE_CLIENT_SECRET!, redirectUri: 'http://localhost:3000/auth/google/callback'}Microsoft
Section titled “Microsoft”microsoft: { clientId: process.env.MICROSOFT_CLIENT_ID!, clientSecret: process.env.MICROSOFT_CLIENT_SECRET!, redirectUri: 'http://localhost:3000/auth/microsoft/callback', tenantId: 'common' // or your tenant ID}apple: { clientId: process.env.APPLE_CLIENT_ID!, clientSecret: process.env.APPLE_CLIENT_SECRET!, redirectUri: 'http://localhost:3000/auth/apple/callback', teamId: process.env.APPLE_TEAM_ID!, keyId: process.env.APPLE_KEY_ID!}auth0: { clientId: process.env.AUTH0_CLIENT_ID!, clientSecret: process.env.AUTH0_CLIENT_SECRET!, redirectUri: 'http://localhost:3000/auth/auth0/callback', domain: 'your-tenant.auth0.com'}okta: { clientId: process.env.OKTA_CLIENT_ID!, clientSecret: process.env.OKTA_CLIENT_SECRET!, redirectUri: 'http://localhost:3000/auth/okta/callback', domain: 'your-domain.okta.com'}Custom OAuth2
Section titled “Custom OAuth2”oauth2: { clientId: 'your-client-id', clientSecret: 'your-client-secret', redirectUri: 'http://localhost:3000/auth/custom/callback', authUrl: 'https://provider.com/oauth/authorize', tokenUrl: 'https://provider.com/oauth/token', userInfoUrl: 'https://provider.com/oauth/userinfo'}Auth Routes
Section titled “Auth Routes”The plugin automatically creates these routes:
GET /auth/{provider}- Initiate OAuth flowGET /auth/{provider}/callback- OAuth callbackGET /auth/logout- LogoutGET /auth/me- Get current user (protected)
Example flow:
1. User visits → GET /auth/github2. Redirected to GitHub OAuth3. User authorizes4. Callback → GET /auth/github/callback5. JWT cookie set6. Redirected to your appProtecting Routes
Section titled “Protecting Routes”Use the auth middleware to protect routes:
// Single routeapp.get('/profile', auth.middleware(), (ctx) => { return ctx.state.user;});
// Multiple routesconst protectedRouter = new ShokupanRouter();protectedRouter.use(auth.middleware());
protectedRouter.get('/profile', (ctx) => ({ user: ctx.state.user }));protectedRouter.get('/settings', (ctx) => ({ settings: {} }));
app.mount('/api', protectedRouter);With Controllers
Section titled “With Controllers”import { Use } from 'shokupan';
@Use(auth.middleware())export class UserController { @Get('/profile') getProfile(@Ctx() ctx: any) { return ctx.state.user; }}JWT Configuration
Section titled “JWT Configuration”Configure JWT tokens:
const auth = new AuthPlugin({ jwtSecret: process.env.JWT_SECRET!, jwtExpiration: '7d', // or: '1h', '30d', etc.
cookieOptions: { httpOnly: true, // Prevent XSS secure: true, // HTTPS only sameSite: 'lax', // CSRF protection maxAge: 7 * 24 * 60 * 60 * 1000 // 7 days }});User Object
Section titled “User Object”After authentication, the user object is available at ctx.state.user:
app.get('/me', auth.middleware(), (ctx) => { const user = ctx.state.user; // { // id: 'github:12345', // email: 'user@example.com', // name: 'John Doe', // avatar: 'https://...', // provider: 'github' // } return user;});Frontend Integration
Section titled “Frontend Integration”OAuth Flow
Section titled “OAuth Flow”// In your frontendfunction login(provider: string) { window.location.href = `http://localhost:3000/auth/${provider}`;}
// Button<button onclick="login('github')">Login with GitHub</button>Check Auth Status
Section titled “Check Auth Status”async function checkAuth() { const response = await fetch('http://localhost:3000/auth/me', { credentials: 'include' // Send cookies });
if (response.ok) { const user = await response.json(); return user; }
return null;}Logout
Section titled “Logout”async function logout() { await fetch('http://localhost:3000/auth/logout', { credentials: 'include' });
// Redirect or update UI}Environment Variables
Section titled “Environment Variables”Create a .env file:
# JWTJWT_SECRET=your-super-secret-key-change-this
# GitHubGITHUB_CLIENT_ID=your-github-client-idGITHUB_CLIENT_SECRET=your-github-client-secret
# GoogleGOOGLE_CLIENT_ID=your-google-client-idGOOGLE_CLIENT_SECRET=your-google-client-secret
# MicrosoftMICROSOFT_CLIENT_ID=your-microsoft-client-idMICROSOFT_CLIENT_SECRET=your-microsoft-client-secretMICROSOFT_TENANT_ID=commonSecurity Best Practices
Section titled “Security Best Practices”const auth = new AuthPlugin({ jwtSecret: process.env.JWT_SECRET!, // Strong, random secret jwtExpiration: '1h', // Short expiration
cookieOptions: { httpOnly: true, // Prevent XSS secure: process.env.NODE_ENV === 'production', // HTTPS only sameSite: 'strict', // Strong CSRF protection maxAge: 60 * 60 * 1000 // 1 hour }});Next Steps
Section titled “Next Steps”- Sessions - Session management
- Validation - Validate user input
- Rate Limiting - Protect auth endpoints