cap-oauth-middleware
v0.1.0
Published
Express middleware for IAS OIDC login, session cookies, and CSRF — lightweight approuter replacement for CAP apps on App Foundation
Readme
cap-oauth-middleware
Express middleware for IAS OIDC login, session cookies, and CSRF — lightweight approuter replacement for CAP apps on App Foundation.
Overview
This middleware provides browser-based OIDC authentication for CAP Node.js apps deployed on App Foundation. It replaces the need for a separate approuter container since UGW already blocks unauthenticated requests at the infrastructure level.
Key Design: Uses a public OIDC client with PKCE — no service binding to identity needed. The middleware discovers IAS endpoints from a well-known URL and uses the authorization code flow with PKCE (code_challenge).
Features
- OIDC login via IAS with PKCE (no client_secret required)
- Encrypted session cookies (iron-webcrypto)
- Automatic token refresh
- CSRF protection (double-submit cookie pattern)
- Auto-detection of IAS URL from env vars, K8s bindings, or VCAP_SERVICES
- Zero native dependencies
- Graceful dev-mode fallback (passthrough when no IAS configured)
Installation
npm install cap-oauth-middlewareQuick Start
In srv/server.js:
const cds = require('@sap/cds');
const { authMiddleware } = require('cap-oauth-middleware');
cds.on('bootstrap', (app) => {
app.use(authMiddleware({
exclude: ['/health', '/ready'],
}));
});
module.exports = cds.server;In asset.yaml:
container:
env:
IAS_URL: "https://sapdasdev.accounts400.ondemand.com"
IAS_CLIENT_ID: "build-apps-public"Configuration
authMiddleware({
// IAS issuer URL (auto-detected from env/bindings if not set)
issuerUrl: 'https://sapdasdev.accounts400.ondemand.com',
// Public client ID (PKCE — no secret needed)
clientId: 'build-apps-public',
// Session options
session: {
secret: process.env.SESSION_SECRET, // auto-generated if not set
maxAge: 3600, // 1 hour (seconds)
cookieName: '__session',
secure: true, // default: true in production
sameSite: 'lax',
},
// Route paths
loginPath: '/login',
callbackPath: '/login/callback',
logoutPath: '/logout',
// Where to redirect after login
defaultRedirect: '/',
// CSRF config
csrf: {
enabled: true,
cookieName: 'XSRF-TOKEN',
headerName: 'X-XSRF-TOKEN',
},
// Routes that skip auth
exclude: ['/health', '/ready'],
// OIDC scopes
scope: 'openid email profile',
})How It Works
- Login:
GET /loginredirects to IAS authorize endpoint with PKCE challenge - Callback:
GET /login/callbackexchanges code for tokens (using code_verifier) - Session: Tokens stored in encrypted httpOnly cookie
- Auth Check: Subsequent requests read session cookie → set
req.user - Refresh: Expired tokens auto-refresh via refresh_token grant
- CSRF: Mutating requests require
X-XSRF-TOKENheader matchingXSRF-TOKENcookie
Environment Variables
| Variable | Description |
|----------|-------------|
| IAS_URL | IAS issuer URL |
| IAS_CLIENT_ID | Public client ID |
| IAS_PUBLIC_CLIENT_ID | Alternative client ID env var |
| SERVICE_BINDING_ROOT | K8s binding root path |
Dev Mode
When no IAS URL or client ID is detected, the middleware passes through all requests (no auth enforced). This allows local development without IAS configuration.
License
SEE LICENSE IN LICENSE
