Optare v1.0 is now available. Get started →
Quickstarts
Node.js / Express

Protect Your Node.js API

This quickstart shows how to validate access tokens in an Express.js API.

Prerequisites

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-node

Create tsconfig.json:

{
  "compilerOptions": {
    "target": "ES2020",
    "module": "commonjs",
    "strict": true,
    "esModuleInterop": true,
    "outDir": "dist"
  }
}

2. Install the SDK

npm install @optare/optareid-js jose

3. Get Your API Credentials

  1. Log in to Optare Console (opens in a new tab)
  2. Go to APIsCreate API
  3. Set an Identifier (e.g., https://api.myapp.com)
  4. 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=3001

5. 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.ts

8. 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/me

Advanced: 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