Protect Your Node.js API
This quickstart shows how to validate access tokens in an Express.js API.
Prerequisites
- Node.js 18+ installed
- An Optare account (sign up free (opens in a new tab))
- An Express.js API (or we'll create one)
1. Create an Express App (Optional)
mkdir my-api && cd my-api
npm init -y
npm install express
npm install -D typescript @types/node @types/express ts-nodeCreate tsconfig.json:
{
"compilerOptions": {
"target": "ES2020",
"module": "commonjs",
"strict": true,
"esModuleInterop": true,
"outDir": "dist"
}
}2. Install the SDK
npm install @optare/optareid-js jose3. Get Your API Credentials
- Log in to Optare Console (opens in a new tab)
- Go to APIs → Create API
- Set an Identifier (e.g.,
https://api.myapp.com) - Note your API Identifier (used as audience)
4. Configure Environment Variables
Create .env:
OPTARE_DOMAIN=https://id.optare.one
OPTARE_AUDIENCE=https://api.myapp.com
PORT=30015. Create Token Validation Middleware
Create src/middleware/auth.ts:
import { Request, Response, NextFunction } from 'express';
import * as jose from 'jose';
const JWKS = jose.createRemoteJWKSet(
new URL(`${process.env.OPTARE_DOMAIN}/.well-known/jwks.json`)
);
export interface AuthRequest extends Request {
user?: {
sub: string;
email?: string;
organizationId?: string;
};
}
export async function requireAuth(
req: AuthRequest,
res: Response,
next: NextFunction
) {
try {
const authHeader = req.headers.authorization;
if (!authHeader?.startsWith('Bearer ')) {
return res.status(401).json({ error: 'Missing authorization header' });
}
const token = authHeader.substring(7);
const { payload } = await jose.jwtVerify(token, JWKS, {
issuer: process.env.OPTARE_DOMAIN,
audience: process.env.OPTARE_AUDIENCE,
});
req.user = {
sub: payload.sub as string,
email: payload.email as string,
organizationId: payload.org_id as string,
};
next();
} catch (error) {
console.error('Token validation failed:', error);
return res.status(401).json({ error: 'Invalid token' });
}
}6. Create Your API
Create src/index.ts:
import express from 'express';
import { requireAuth, AuthRequest } from './middleware/auth';
import 'dotenv/config';
const app = express();
app.use(express.json());
// Public endpoint
app.get('/health', (req, res) => {
res.json({ status: 'ok' });
});
// Protected endpoint
app.get('/api/me', requireAuth, (req: AuthRequest, res) => {
res.json({
userId: req.user?.sub,
email: req.user?.email,
organizationId: req.user?.organizationId,
});
});
// Protected endpoint with organization context
app.get('/api/data', requireAuth, async (req: AuthRequest, res) => {
const { organizationId } = req.user!;
// Fetch data scoped to the user's organization
res.json({
message: `Data for organization ${organizationId}`,
items: [],
});
});
const PORT = process.env.PORT || 3001;
app.listen(PORT, () => {
console.log(`API running on http://localhost:${PORT}`);
});7. Run Your API
npx ts-node src/index.ts8. Test with curl
# Get a token from your frontend app or use the CLI
TOKEN="your_access_token"
# Call protected endpoint
curl -H "Authorization: Bearer $TOKEN" http://localhost:3001/api/meAdvanced: Check Licenses/Entitlements
import { OptareClient } from '@optare/optareid-js';
// In your route handler
app.get('/api/premium-feature', requireAuth, async (req: AuthRequest, res) => {
const client = new OptareClient({
baseUrl: process.env.OPTARE_DOMAIN!,
token: req.headers.authorization?.substring(7),
});
const hasAccess = await client.license.check('premium-feature');
if (!hasAccess) {
return res.status(403).json({ error: 'Upgrade required' });
}
res.json({ data: 'Premium content here' });
});Next Steps
- Management SDK - Server-side user/org management
- Webhooks - React to auth events
- Multi-tenancy - Organization isolation