Skip to Content
🚀 Alpha Release - Yama JS is currently in alpha. APIs may change without notice.
DocumentationGuidesAuthentication

Authentication

Yama provides built-in JWT authentication and authorization rules to secure your API.

Enable Authentication

Configure authentication in yama.yaml:

auth: providers: - type: jwt secret: ${JWT_SECRET} expiresIn: 7d

Protect Endpoints

Use auth rules on endpoints:

endpoints: # Public endpoint - no authentication required /health: get: handler: handlers/health auth: public # Authenticated endpoint - requires valid JWT /profile: get: handler: handlers/getProfile auth: required # Role-based access /admin/users: get: handler: handlers/adminListUsers auth: role: admin

Auth Levels

LevelDescription
publicNo authentication required
requiredValid JWT token required
optionalToken validated if present, but not required
{ role: 'admin' }Requires specific role

Login Handler

Create a login endpoint:

endpoints: /auth/login: post: handler: handlers/login auth: public request: type: object properties: email: type: string password: type: string
// src/handlers/login.ts import { HandlerContext } from '@betagors/yama-core'; import { sign } from 'jsonwebtoken'; export async function login(context: HandlerContext) { const { email, password } = context.request.body; // Verify credentials const user = await context.db.query( 'SELECT * FROM users WHERE email = $1', [email] ); if (!user.length || !verifyPassword(password, user[0].password_hash)) { context.reply.code(401); return { error: 'Invalid credentials' }; } // Generate JWT const token = sign( { userId: user[0].id, email: user[0].email }, process.env.JWT_SECRET, { expiresIn: '7d' } ); return { token, user: user[0] }; }

Register Handler

// src/handlers/register.ts import { HandlerContext } from '@betagors/yama-core'; import { hash } from 'bcrypt'; export async function register(context: HandlerContext) { const { email, password, name } = context.request.body; // Check if user exists const existing = await context.db.query( 'SELECT id FROM users WHERE email = $1', [email] ); if (existing.length) { context.reply.code(409); return { error: 'Email already registered' }; } // Hash password and create user const passwordHash = await hash(password, 10); const [user] = await context.db.query( 'INSERT INTO users (email, password_hash, name) VALUES ($1, $2, $3) RETURNING id, email, name', [email, passwordHash, name] ); return user; }

Access User in Handlers

export async function getProfile(context: HandlerContext) { // User is automatically available from JWT const { user } = context.auth; return { id: user.id, email: user.email, name: user.name, }; }

Role-Based Access Control

Define roles in your user schema:

schemas: User: type: object properties: id: type: string email: type: string role: type: string enum: - user - admin - moderator

Protect endpoints by role:

endpoints: /admin/dashboard: get: handler: handlers/adminDashboard auth: role: admin /moderator/reports: get: handler: handlers/moderatorReports auth: role: - admin - moderator

Custom Authorization

For complex authorization logic, handle it in your handler:

export async function updatePost(context: HandlerContext) { const { id } = context.params; const { user } = context.auth; // Fetch the post const [post] = await context.db.query( 'SELECT * FROM posts WHERE id = $1', [id] ); if (!post) { context.reply.code(404); return { error: 'Post not found' }; } // Check ownership or admin role if (post.author_id !== user.id && user.role !== 'admin') { context.reply.code(403); return { error: 'Not authorized to edit this post' }; } // Update the post const { title, content } = context.request.body; const [updated] = await context.db.query( 'UPDATE posts SET title = $1, content = $2 WHERE id = $3 RETURNING *', [title, content, id] ); return updated; }

Token Refresh

Implement token refresh for long-lived sessions:

endpoints: /auth/refresh: post: handler: handlers/refreshToken auth: required
export async function refreshToken(context: HandlerContext) { const { user } = context.auth; const token = sign( { userId: user.id, email: user.email }, process.env.JWT_SECRET, { expiresIn: '7d' } ); return { token }; }

Best Practices

  1. Use strong secrets — Generate a random 256-bit secret for JWT
  2. Set appropriate expiration — Balance security and user experience
  3. Store password hashes — Never store plain text passwords
  4. Use HTTPS — Always use HTTPS in production
  5. Validate input — Sanitize all user input before use
Last updated on