npm install authsafe-express cookie-parseryarn add authsafe-express cookie-parserpnpm add authsafe-express cookie-parser.env file in your project root:
# Required
AUTHSAFE_CLIENT_ID=your_client_id_here
AUTHSAFE_CLIENT_SECRET=your_client_secret_here
AUTHSAFE_DOMAIN=https://auth.yourapp.com
# Optional
APP_URL=http://localhost:3000
NODE_ENV=developmentimport express from 'express';
import cookieParser from 'cookie-parser';
const app = express();
// Required: Parse cookies
app.use(cookieParser());initAuthSafe() once during app initialization:
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`,
});interface AuthSafeConfig {
/** OAuth2 client ID from AuthSafe dashboard */
clientId: string;
/** OAuth2 client secret (required for token exchange) */
clientSecret?: string;
/** AuthSafe domain (e.g., 'https://auth.yourapp.com') */
domain: string;
/** Redirect URI after authentication */
redirectUri?: string;
/** Scopes to request (defaults to ['openid', 'email', 'profile']) */
scopes?: string[];
/** Cookie configuration */
cookies?: {
prefix?: string;
domain?: string;
path?: string;
secure?: boolean;
sameSite?: 'strict' | 'lax' | 'none';
};
/** Session configuration */
session?: {
maxAge?: number;
};
}| Parameter | Type | Required | Description |
|---|---|---|---|
clientId | string | Yes | OAuth2 client ID from dashboard |
clientSecret | string | No* | Required for token exchange and refresh |
domain | string | Yes | Your AuthSafe domain URL |
redirectUri | string | No | Callback URL (defaults to /auth/callback) |
scopes | string[] | No | OAuth scopes to request |
initAuthSafe({
clientId: process.env.AUTHSAFE_CLIENT_ID!,
clientSecret: process.env.AUTHSAFE_CLIENT_SECRET!,
domain: process.env.AUTHSAFE_DOMAIN!,
scopes: [
'openid',
'email',
'profile',
'offline_access', // For refresh tokens
'admin:read', // Custom scope
'admin:write',
],
});initAuthSafe({
clientId: process.env.AUTHSAFE_CLIENT_ID!,
clientSecret: process.env.AUTHSAFE_CLIENT_SECRET!,
domain: process.env.AUTHSAFE_DOMAIN!,
cookies: {
prefix: 'myapp', // Cookie name prefix
domain: '.yourapp.com', // Cookie domain
path: '/', // Cookie path
secure: true, // HTTPS only
sameSite: 'lax', // CSRF protection
},
});initAuthSafe({
clientId: process.env.AUTHSAFE_CLIENT_ID!,
clientSecret: process.env.AUTHSAFE_CLIENT_SECRET!,
domain: process.env.AUTHSAFE_DOMAIN!,
session: {
maxAge: 7 * 24 * 60 * 60, // 7 days in seconds
},
});import express from 'express';
import cookieParser from 'cookie-parser';
import {
initAuthSafe,
requireAuth,
optionalAuth,
handleSignIn,
handleCallback,
handleLogout,
handleRefresh,
} from 'authsafe-express';
const app = express();
// Middleware
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
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.APP_URL}/auth/callback`,
scopes: ['openid', 'email', 'profile', 'offline_access'],
cookies: {
secure: process.env.NODE_ENV === 'production',
sameSite: 'lax',
},
session: {
maxAge: 24 * 60 * 60, // 24 hours
},
});
// Auth routes
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`,
});
});
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`,
});
});
app.post('/auth/logout', (req, res) => {
handleLogout(req, res, {
clientId: process.env.AUTHSAFE_CLIENT_ID!,
domain: process.env.AUTHSAFE_DOMAIN!,
});
});
app.post('/auth/refresh', (req, res) => {
handleRefresh(req, res, {
clientId: process.env.AUTHSAFE_CLIENT_ID!,
clientSecret: process.env.AUTHSAFE_CLIENT_SECRET!,
domain: process.env.AUTHSAFE_DOMAIN!,
});
});
// Public routes
app.get('/', (req, res) => {
res.json({ message: 'Public home page' });
});
app.get('/about', optionalAuth(), (req, res) => {
if (req.auth) {
res.json({ message: `Hello ${req.auth.email}` });
} else {
res.json({ message: 'Hello guest' });
}
});
// Protected routes
app.get('/dashboard', requireAuth(), (req, res) => {
res.json({
message: 'Dashboard',
user: req.auth,
});
});
// Error handling
app.use((err: any, req: any, res: any, next: any) => {
console.error('Error:', err);
res.status(500).json({ error: 'Internal server error' });
});
// Start server
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Server running on http://localhost:${PORT}`);
});npm install -D @types/express @types/cookie-parser{
"compilerOptions": {
"target": "ES2022",
"module": "commonjs",
"lib": ["ES2022"],
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"moduleResolution": "node"
},
"include": ["src/**/*"],
"exclude": ["node_modules"]
}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,
});
});// config/development.ts
export const authConfig = {
clientId: process.env.AUTHSAFE_CLIENT_ID!,
clientSecret: process.env.AUTHSAFE_CLIENT_SECRET!,
domain: 'http://localhost:8000',
redirectUri: 'http://localhost:3000/auth/callback',
cookies: {
secure: false, // Allow HTTP in dev
sameSite: 'lax' as const,
},
};// config/production.ts
export const authConfig = {
clientId: process.env.AUTHSAFE_CLIENT_ID!,
clientSecret: process.env.AUTHSAFE_CLIENT_SECRET!,
domain: process.env.AUTHSAFE_DOMAIN!,
redirectUri: process.env.REDIRECT_URI!,
cookies: {
secure: true, // HTTPS only
sameSite: 'lax' as const,
domain: '.yourapp.com',
},
session: {
maxAge: 7 * 24 * 60 * 60, // 7 days
},
};import { authConfig } from `./config/${process.env.NODE_ENV}`;
import { initAuthSafe } from 'authsafe-express';
initAuthSafe(authConfig);app.use(cookieParser()); // ✅ Before auth routes
app.get('/auth/callback', handleCallback);initAuthSafe({
// ...
cookies: {
secure: true, // Requires HTTPS
},
});import cors from 'cors';
app.use(
cors({
origin: process.env.FRONTEND_URL,
credentials: true, // Allow cookies
}),
);