initAuthSafe() - Initialize global configurationrequireAuth() - Require authenticationoptionalAuth() - Optional authenticationrequireScope() - Require specific scopesrequireAnyScope() - Require any of specified scopesfunction initAuthSafe(config: AuthSafeConfig): void;import { initAuthSafe } from 'authsafe-express';
initAuthSafe({
clientId: process.env.AUTHSAFE_CLIENT_ID!,
clientSecret: process.env.AUTHSAFE_CLIENT_SECRET!,
domain: process.env.AUTHSAFE_DOMAIN!,
redirectUri: `${process.env.APP_URL}/auth/callback`,
});function requireAuth(options?: {
autoRefresh?: boolean;
onUnauthorized?: (req: Request, res: Response) => void;
}): RequestHandler;| Option | Type | Default | Description |
|---|---|---|---|
autoRefresh | boolean | false | Automatically refresh expired tokens |
onUnauthorized | function | - | Custom handler for unauthorized requests |
import { requireAuth } from 'authsafe-express';
app.get('/dashboard', requireAuth(), (req, res) => {
res.json({
message: `Welcome ${req.auth.email}`,
user: req.auth,
});
});app.get('/profile', requireAuth({ autoRefresh: true }), (req, res) => {
res.json({ user: req.auth });
});app.get(
'/dashboard',
requireAuth({
onUnauthorized: (req, res) => {
res.redirect('/login');
},
}),
(req, res) => {
res.json({ user: req.auth });
},
);import type { AuthenticatedRequest } from 'authsafe-express';
app.get('/profile', requireAuth(), (req: AuthenticatedRequest, res) => {
// req.auth is fully typed
const { userId, email, scopes, organizationId } = req.auth;
res.json({ userId, email, scopes, organizationId });
});function optionalAuth(options?: { autoRefresh?: boolean }): RequestHandler;import { optionalAuth } from 'authsafe-express';
app.get('/home', optionalAuth(), (req, res) => {
if (req.auth) {
res.json({ message: `Welcome back, ${req.auth.email}` });
} else {
res.json({ message: 'Welcome, guest!' });
}
});app.get('/blog', optionalAuth(), (req, res) => {
const posts = getPosts();
if (req.auth) {
// Include private posts for authenticated users
const privatePosts = getPrivatePosts(req.auth.userId);
res.json({ posts: [...posts, ...privatePosts] });
} else {
res.json({ posts });
}
});requireAuth().
function requireScope(...scopes: string[]): RequestHandler;import { requireAuth, requireScope } from 'authsafe-express';
app.delete(
'/admin/users/:id',
requireAuth(),
requireScope('admin:delete'),
(req, res) => {
res.json({ message: 'User deleted' });
},
);app.post(
'/admin/settings',
requireAuth(),
requireScope('admin:read', 'admin:write'),
(req, res) => {
res.json({ message: 'Settings updated' });
},
);{
"error": "forbidden",
"message": "Insufficient permissions",
"required_scopes": ["admin:delete"]
}requireAuth().
function requireAnyScope(...scopes: string[]): RequestHandler;import { requireAuth, requireAnyScope } from 'authsafe-express';
app.get(
'/reports',
requireAuth(),
requireAnyScope('reports:read', 'admin:read'),
(req, res) => {
res.json({ reports: getReports() });
},
);app.post(
'/content',
requireAuth(),
requireAnyScope('content:create', 'editor', 'admin'),
(req, res) => {
res.json({ message: 'Content created' });
},
);req.auth object attached by middleware:
interface AuthSession {
/** User ID (extracted from 'sub' claim) */
userId: string;
/** User email */
email: string;
/** User full name */
name?: string;
/** Email verified status */
emailVerified: boolean;
/** Organization ID */
organizationId: string;
/** Token scopes */
scopes: string[];
/** Issued at timestamp (seconds) */
issuedAt: number;
/** Expires at timestamp (seconds) */
expiresAt: number;
}import express from 'express';
import { requireAuth, requireScope, requireAnyScope } from 'authsafe-express';
const app = express();
// Public endpoint
app.get('/api/public', (req, res) => {
res.json({ message: 'Public data' });
});
// Authenticated endpoint
app.get('/api/user/profile', requireAuth(), (req, res) => {
res.json({ user: req.auth });
});
// Scope-protected endpoint
app.post(
'/api/admin/users',
requireAuth(),
requireScope('admin:create'),
(req, res) => {
res.json({ message: 'User created' });
},
);
// Multiple scope options
app.get(
'/api/analytics',
requireAuth(),
requireAnyScope('analytics:read', 'admin:read'),
(req, res) => {
res.json({ analytics: getAnalytics() });
},
);// Middleware to check user roles
function requireRole(...roles: string[]) {
return (req: any, res: any, next: any) => {
if (!req.auth) {
return res.status(401).json({ error: 'Unauthorized' });
}
const hasRole = roles.some((role) =>
req.auth.scopes.includes(`role:${role}`),
);
if (!hasRole) {
return res.status(403).json({
error: 'Forbidden',
required_roles: roles,
});
}
next();
};
}
// Use role middleware
app.get(
'/admin/dashboard',
requireAuth(),
requireRole('admin', 'moderator'),
(req, res) => {
res.json({ message: 'Admin dashboard' });
},
);const router = express.Router();
// List resources (read permission)
router.get('/', requireAuth(), requireScope('resources:read'), (req, res) => {
res.json({ resources: getResources() });
});
// Create resource (write permission)
router.post('/', requireAuth(), requireScope('resources:write'), (req, res) => {
const resource = createResource(req.body);
res.json({ resource });
});
// Update resource (write permission)
router.put(
'/:id',
requireAuth(),
requireScope('resources:write'),
(req, res) => {
const resource = updateResource(req.params.id, req.body);
res.json({ resource });
},
);
// Delete resource (delete permission)
router.delete(
'/:id',
requireAuth(),
requireScope('resources:delete'),
(req, res) => {
deleteResource(req.params.id);
res.json({ message: 'Deleted' });
},
);
app.use('/api/resources', router);app.get('/api/organizations/:orgId/data', requireAuth(), (req, res) => {
const { orgId } = req.params;
// Verify user belongs to organization
if (req.auth.organizationId !== orgId) {
return res.status(403).json({
error: 'Access denied to this organization',
});
}
res.json({
organization: orgId,
data: getOrganizationData(orgId),
});
});{
"error": "unauthorized",
"message": "Authentication required"
}{
"error": "forbidden",
"message": "Insufficient permissions",
"required_scopes": ["admin:delete"]
}app.use((err: any, req: any, res: any, next: any) => {
console.error('Auth error:', err);
if (err.status === 401) {
return res.status(401).json({
error: 'Unauthorized',
message: 'Please sign in',
});
}
if (err.status === 403) {
return res.status(403).json({
error: 'Forbidden',
message: 'Insufficient permissions',
});
}
res.status(500).json({ error: 'Internal server error' });
});requireAuth() before scope middleware - Scope checks require authoptionalAuth() for public routes - Enhance UX for logged-in usersinitAuthSafe() is called before using middleware:
// ✅ Correct order
initAuthSafe(config);
app.get('/dashboard', requireAuth(), handler);
// ❌ Wrong order
app.get('/dashboard', requireAuth(), handler);
initAuthSafe(config);requireAuth() to ensure auth session exists:
// ✅ Correct
app.get('/profile', requireAuth(), (req, res) => {
console.log(req.auth.email);
});
// ❌ Wrong - auth might be undefined
app.get('/profile', (req, res) => {
console.log(req.auth?.email);
});