authsafe-express
v0.0.5
Published
Official Express.js SDK for AuthSafe - OAuth 2.1, OIDC, and MFA middleware for Express applications
Maintainers
Readme
AuthSafe Express SDK
The official Express.js SDK for AuthSafe — secure OAuth 2.1, OIDC, and MFA middleware for Express applications.
Features
- ✅ Express 4+ & 5+ - Compatible with Express.js 4.x and 5.x
- ✅ Middleware - Drop-in authentication middleware
- ✅ PKCE Flow - Secure authorization code flow with PKCE
- ✅ JWT Validation - JWKS-based token verification with caching
- ✅ Scope Protection - Route-level scope enforcement
- ✅ Auto Refresh - Optional automatic token refresh
- ✅ TypeScript First - Comprehensive type definitions
- ✅ Cookie-based Sessions - Secure HTTP-only cookies
Installation
npm install authsafe-expressAlso install cookie-parser (peer dependency):
npm install cookie-parserOr with other package managers:
# Yarn
yarn add authsafe-express cookie-parser
# pnpm
pnpm add authsafe-express cookie-parserQuick Start
1. Basic Setup
import express from 'express';
import cookieParser from 'cookie-parser';
import { initAuthSafe, requireAuth } from 'authsafe-express';
const app = express();
// Required: cookie-parser middleware
app.use(cookieParser());
// Initialize AuthSafe
initAuthSafe({
clientId: process.env.AUTHSAFE_CLIENT_ID!,
clientSecret: process.env.AUTHSAFE_CLIENT_SECRET!,
domain: process.env.AUTHSAFE_DOMAIN!,
redirectUri: process.env.AUTHSAFE_REDIRECT_URI,
});
// Protected route
app.get('/dashboard', requireAuth(), (req, res) => {
res.json({ user: req.auth });
});
app.listen(3000);2. OAuth Routes
import { handleCallback, handleSignIn, handleLogout } from 'authsafe-express';
// Sign in
app.get('/auth/signin', (req, res) => {
handleSignIn(req, res, {
clientId: process.env.AUTHSAFE_CLIENT_ID!,
domain: process.env.AUTHSAFE_DOMAIN!,
redirectUri: `${process.env.APP_URL}/auth/callback`,
});
});
// Callback
app.get('/auth/callback', (req, res) => {
handleCallback(req, res, {
clientId: process.env.AUTHSAFE_CLIENT_ID!,
clientSecret: process.env.AUTHSAFE_CLIENT_SECRET!,
domain: process.env.AUTHSAFE_DOMAIN!,
redirectUri: `${process.env.APP_URL}/auth/callback`,
});
});
// Logout
app.post('/auth/logout', (req, res) => {
handleLogout(req, res, {
clientId: process.env.AUTHSAFE_CLIENT_ID!,
domain: process.env.AUTHSAFE_DOMAIN!,
});
});Usage
Require Authentication
import { requireAuth } from 'authsafe-express';
app.get('/profile', requireAuth(), (req, res) => {
// req.auth contains the authenticated user session
res.json({
userId: req.auth.userId,
email: req.auth.email,
name: req.auth.name,
});
});Optional Authentication
import { optionalAuth } from 'authsafe-express';
app.get('/public', optionalAuth(), (req, res) => {
if (req.auth) {
res.json({ message: `Hello ${req.auth.email}` });
} else {
res.json({ message: 'Hello guest' });
}
});Scope-based Authorization
import { requireAuth, requireScope } from 'authsafe-express';
// Require specific scope
app.delete(
'/admin/users/:id',
requireAuth(),
requireScope('admin:delete'),
(req, res) => {
// User has admin:delete scope
res.json({ success: true });
},
);
// Require multiple scopes
app.post(
'/admin/settings',
requireAuth(),
requireScope('admin:write', 'settings:manage'),
(req, res) => {
// User has both scopes
res.json({ success: true });
},
);Require Any of Multiple Scopes
import { requireAuth, requireAnyScope } from 'authsafe-express';
app.get(
'/reports',
requireAuth(),
requireAnyScope('reports:read', 'admin:read'),
(req, res) => {
// User has at least one of the scopes
res.json({ reports: [] });
},
);Auto Token Refresh
import { requireAuth } from 'authsafe-express';
app.get('/dashboard', requireAuth({ autoRefresh: true }), (req, res) => {
// Tokens will be automatically refreshed if expired
res.json({ user: req.auth });
});Custom Unauthorized Handler
import { requireAuth } from 'authsafe-express';
app.get(
'/api/data',
requireAuth({
onUnauthorized: (req, res) => {
res.status(401).json({
error: 'Please log in to access this resource',
redirectTo: '/login',
});
},
}),
(req, res) => {
res.json({ data: [] });
},
);API Reference
Initialization
initAuthSafe(config: AuthSafeConfig): voidInitialize AuthSafe with configuration. Call once at app startup.
Middleware
requireAuth(options?: {
autoRefresh?: boolean;
onUnauthorized?: (req, res) => void;
}): RequestHandlerRequire authentication. Blocks request if user is not authenticated.
optionalAuth(options?: {
autoRefresh?: boolean;
}): RequestHandlerOptionally attach auth session. Does not block if not authenticated.
requireScope(...scopes: string[]): RequestHandlerRequire all specified scopes. Must be used after requireAuth().
requireAnyScope(...scopes: string[]): RequestHandlerRequire any of the specified scopes. Must be used after requireAuth().
Route Handlers
handleCallback(req, res, config): Promise<void>
handleSignIn(req, res, config): Promise<void>
handleLogout(req, res, config): Promise<void>
handleRefresh(req, res, config): Promise<void>OAuth flow handlers for routes.
Session Management
setAuthCookies(res, tokens, config): void
getAuthCookies(req, config): AuthTokens | null
clearAuthCookies(res, config): void
refreshTokens(refreshToken, config): Promise<AuthTokens>Cookie and session management utilities.
JWT Utilities
verifyToken(token, domain, clientId, organizationId): Promise<AuthSafeJWTPayload>
decodeToken(token): AuthSafeJWTPayload | null
extractUserId(sub): string
isClientToken(sub): boolean
isTokenExpired(exp): boolean
shouldRefreshToken(exp): booleanJWT validation and inspection utilities.
TypeScript
The SDK is written in TypeScript with full type definitions:
import type {
AuthSafeConfig,
AuthSession,
AuthTokens,
AuthenticatedRequest,
AuthSafeJWTPayload,
} from 'authsafe-express';
// Your Express request is augmented with auth
app.get('/api', requireAuth(), (req: AuthenticatedRequest, res) => {
// req.auth is typed as AuthSession
const userId = req.auth.userId;
});Examples
Complete Express + TypeScript App
import express from 'express';
import cookieParser from 'cookie-parser';
import {
initAuthSafe,
requireAuth,
requireScope,
handleCallback,
handleSignIn,
handleLogout,
} from 'authsafe-express';
const app = express();
app.use(cookieParser());
initAuthSafe({
clientId: process.env.AUTHSAFE_CLIENT_ID!,
clientSecret: process.env.AUTHSAFE_CLIENT_SECRET!,
domain: process.env.AUTHSAFE_DOMAIN!,
});
// Auth routes
app.get('/auth/signin', (req, res) => handleSignIn(req, res, {...}));
app.get('/auth/callback', (req, res) => handleCallback(req, res, {...}));
app.post('/auth/logout', (req, res) => handleLogout(req, res, {...}));
// Protected routes
app.get('/profile', requireAuth(), (req, res) => {
res.json(req.auth);
});
app.delete('/users/:id', requireAuth(), requireScope('admin'), (req, res) => {
res.json({ success: true });
});
app.listen(3000);License
MIT
Support
- GitHub: authsafe/authsafe-js
- Documentation: docs.authsafe.in
Made with ❤️ by the AuthSafe team
