Authentication
VentureKit provides authentication through Amazon Cognito with role-based access control (RBAC) and OAuth scope enforcement.
Overview
Section titled “Overview”Authentication in VentureKit works at three levels:
- Security config — define scopes and app clients
- Infrastructure intents — provision a Cognito User Pool
- Handler scopes — enforce authentication per endpoint
1. Define Scopes
Section titled “1. Define Scopes”Scopes are defined once in config/security.ts and shared across all environments:
import type { SecurityConfig } from '@venturekit/core';
export const security: SecurityConfig = { scopes: [ { name: 'users.read', description: 'Read user data' }, { name: 'users.write', description: 'Create and update users' }, { name: 'admin.users', description: 'Admin user management' }, ], appClients: [ { name: 'web-app', allowedScopes: ['users.read', 'users.write'], supportsRefreshTokens: true, }, { name: 'admin-dashboard', allowedScopes: ['users.read', 'users.write', 'admin.users'], supportsRefreshTokens: true, generateSecret: true, }, ], mfa: 'optional',};2. Provision a User Pool
Section titled “2. Provision a User Pool”Use an auth intent to create a Cognito User Pool:
export default defineVenture({ base, security, envs: { dev, prod }, routesDir: 'src/routes', infrastructure: { auth: [{ id: 'main', signInWith: ['email'], allowSignUp: true, mfa: 'optional', passwordStrength: 'strong', }], },});3. Protect Endpoints
Section titled “3. Protect Endpoints”Add scopes to your handler to require authentication:
import { handler } from '@venturekit/runtime';
// Public — no auth requiredexport const main = handler(async (_body, ctx, logger) => { return { status: 'ok' };});
// Authenticated — requires users.read scopeexport const main = handler(async (_body, ctx, logger) => { return { userId: ctx.user?.id, email: ctx.user?.email };}, { scopes: ['users.read'] });
// Admin only — requires admin.users scopeexport const main = handler(async (_body, ctx, logger) => { return { users: [] };}, { scopes: ['admin.users'] });Role-Based Access Control
Section titled “Role-Based Access Control”Define roles that map to sets of scopes:
import type { RolesConfig } from '@venturekit/auth';
const rolesConfig: RolesConfig = { roles: [ { name: 'viewer', description: 'Read only', scopes: ['users.read'] }, { name: 'member', description: 'Standard', scopes: ['users.read', 'users.write'] }, { name: 'admin', description: 'Full access', scopes: ['users.read', 'users.write', 'admin.users'], isSystem: true }, ], defaultRole: 'viewer', superAdminRole: 'admin',};Checking Scopes from Roles
Section titled “Checking Scopes from Roles”import { hasScope, getScopesForRoles, hasAllScopes } from '@venturekit/auth';
getScopesForRoles(['member'], rolesConfig);// → ['users.read', 'users.write']
hasScope(['member'], 'admin.users', rolesConfig);// → false
hasAllScopes(['admin'], ['users.read', 'admin.users'], rolesConfig);// → trueJWT Utilities
Section titled “JWT Utilities”import { decodeToken, extractUserFromToken, isTokenExpired, getTokenExpiry } from '@venturekit/auth';
const claims = decodeToken(jwt); // Decode WITHOUT verificationconst user = extractUserFromToken(jwt); // Extract user from ID tokenconst expired = isTokenExpired(jwt); // Check exp claimconst expiry = getTokenExpiry(jwt); // Get expiry as DateAccessing User Context
Section titled “Accessing User Context”In authenticated handlers, ctx.user is populated automatically:
export const main = handler(async (_body, ctx, logger) => { const user = ctx.user!; logger.info('Request from user', { userId: user.id, email: user.email, scopes: user.scopes, }); return { profile: { id: user.id, email: user.email } };}, { scopes: ['users.read'] });