@eyjs/auth
v1.0.0
Published
Authentication package for EyJS framework with Clerk integration
Maintainers
Readme
@eyjs/auth
Authentication package for the EyJS framework with Clerk integration. Provides decorator-based authentication, JWT token verification, and seamless integration with EyJS applications.
Features
- 🔐 Clerk Integration - Full support for Clerk authentication
- 🎯 Decorator-Based Auth - Simple
@UseAuth()decorator for protecting routes - 🔑 JWT Token Verification - Secure token validation and user extraction
- 🛡️ Middleware Support - Flexible authentication middleware
- 🔧 TypeScript Support - Full TypeScript definitions and type safety
- ⚡ EyJS Integration - Works seamlessly with EyJS dependency injection
Installation
# Using Bun (recommended)
bun add @eyjs/auth
# Using npm
npm install @eyjs/auth
# Using yarn
yarn add @eyjs/auth
# Using pnpm
pnpm add @eyjs/authPrerequisites
This package requires:
@eyjs/core@^1.0.4- EyJS core framework@eyjs/shared-errors@^1.0.0- Shared error codes
Quick Start
1. Environment Setup
Create a .env file with your Clerk credentials:
CLERK_FRONTEND_API_KEY=pk_test_your_frontend_api_key
CLERK_SECRET_KEY=sk_test_your_secret_key2. Basic Usage
import { UseAuth } from '@eyjs/auth'
import { Controller, Get } from '@eyjs/http-server'
@Controller('/users')
export class UserController {
@Get('/profile')
@UseAuth()
async getProfile() {
// This route requires authentication
// User information is automatically available
return { message: 'Protected route accessed' }
}
@Get('/public')
async getPublicData() {
// This route is public
return { message: 'Public data' }
}
}3. Advanced Authentication
import { UseAuth } from '@eyjs/auth'
import { Controller, Get, Post } from '@eyjs/http-server'
@Controller('/admin')
export class AdminController {
@Get('/dashboard')
@UseAuth({ roles: ['admin'] })
async getDashboard() {
// Only users with 'admin' role can access
return { message: 'Admin dashboard' }
}
@Post('/users')
@UseAuth({ permissions: ['create_user'] })
async createUser() {
// Only users with 'create_user' permission can access
return { message: 'User created' }
}
}API Reference
Decorators
@UseAuth(options?)
Protects a route with authentication.
@UseAuth({
roles?: string[] // Required user roles
permissions?: string[] // Required user permissions
optional?: boolean // Make auth optional
})Options:
roles- Array of required user rolespermissions- Array of required user permissionsoptional- If true, authentication is optional (user can be null)
Middleware
AuthMiddleware
Authentication middleware for manual route protection.
import { AuthMiddleware } from '@eyjs/auth'
// Use in route handlers
app.use('/protected', AuthMiddleware)Usage Examples
Basic Route Protection
import { UseAuth } from '@eyjs/auth'
import { Controller, Get, Post } from '@eyjs/http-server'
@Controller('/api')
export class ApiController {
@Get('/public')
async getPublicData() {
return { data: 'This is public' }
}
@Get('/private')
@UseAuth()
async getPrivateData() {
return { data: 'This is private' }
}
@Post('/create')
@UseAuth()
async createResource() {
return { message: 'Resource created' }
}
}Role-Based Access Control
import { UseAuth } from '@eyjs/auth'
import { Controller, Get, Delete } from '@eyjs/http-server'
@Controller('/admin')
export class AdminController {
@Get('/users')
@UseAuth({ roles: ['admin', 'moderator'] })
async getUsers() {
// Only admins and moderators can access
return { users: [] }
}
@Delete('/users/:id')
@UseAuth({ roles: ['admin'] })
async deleteUser(id: string) {
// Only admins can delete users
return { message: 'User deleted' }
}
}Permission-Based Access Control
import { UseAuth } from '@eyjs/auth'
import { Controller, Post, Put } from '@eyjs/http-server'
@Controller('/content')
export class ContentController {
@Post('/articles')
@UseAuth({ permissions: ['create_article'] })
async createArticle() {
return { message: 'Article created' }
}
@Put('/articles/:id')
@UseAuth({ permissions: ['edit_article'] })
async updateArticle(id: string) {
return { message: 'Article updated' }
}
}Optional Authentication
import { UseAuth } from '@eyjs/auth'
import { Controller, Get } from '@eyjs/http-server'
@Controller('/content')
export class ContentController {
@Get('/articles')
@UseAuth({ optional: true })
async getArticles() {
// Route works for both authenticated and anonymous users
// You can check if user is authenticated inside the method
return { articles: [] }
}
}Custom Authentication Logic
import { UseAuth } from '@eyjs/auth'
import { Controller, Get } from '@eyjs/http-server'
@Controller('/custom')
export class CustomController {
@Get('/special')
@UseAuth()
async getSpecialData(request: any) {
// Access user information from request
const user = request.user
// Custom logic based on user
if (user.email.endsWith('@company.com')) {
return { data: 'Company data' }
}
return { data: 'Regular data' }
}
}Configuration
Environment Variables
| Variable | Description | Required |
|----------|-------------|----------|
| CLERK_FRONTEND_API_KEY | Clerk frontend API key | Yes |
| CLERK_SECRET_KEY | Clerk secret key | Yes |
| CLERK_JWT_KEY | JWT verification key (optional) | No |
Clerk Setup
Create a Clerk Account
- Go to clerk.com
- Create a new application
Get API Keys
- Navigate to API Keys in your Clerk dashboard
- Copy the Frontend API Key and Secret Key
Configure Environment
CLERK_FRONTEND_API_KEY=pk_test_... CLERK_SECRET_KEY=sk_test_...
Error Handling
The package integrates with @eyjs/shared-errors for consistent error handling:
import { ErrorCodes } from '@eyjs/shared-errors'
// Common authentication errors
throw new Error(ErrorCodes.AUTH_MISSING) // No authentication provided
throw new Error(ErrorCodes.AUTH_INVALID) // Invalid token
throw new Error(ErrorCodes.TOKEN_EXPIRED) // Token expired
throw new Error(ErrorCodes.PERMISSION_DENIED) // Insufficient permissionsError Response Format
{
"success": false,
"error": {
"code": "AUTH_MISSING",
"message": "Authentication required",
"timestamp": "2024-01-01T00:00:00.000Z"
}
}Integration with EyJS
Dependency Injection
import { Injectable } from '@eyjs/core'
import { UseAuth } from '@eyjs/auth'
@Injectable()
export class UserService {
@UseAuth()
async getCurrentUser() {
// Service method with authentication
}
}HTTP Server Integration
import { EyJs } from '@eyjs/core'
import { UseAuth } from '@eyjs/auth'
const app = await EyJs.start(import.meta.url)
// All routes with @UseAuth() are automatically protectedTesting
Unit Tests
import { describe, it, expect } from 'bun:test'
import { AuthMiddleware } from '@eyjs/auth'
describe('AuthMiddleware', () => {
it('should authenticate valid token', async () => {
// Test authentication logic
})
it('should reject invalid token', async () => {
// Test error handling
})
})Integration Tests
import { describe, it, expect } from 'bun:test'
describe('Authentication Integration', () => {
it('should protect routes with @UseAuth()', async () => {
// Test protected routes
})
})Troubleshooting
Common Issues
1. "Authentication required" error
- Ensure
CLERK_SECRET_KEYis set correctly - Check that the token is being sent in the Authorization header
2. "Invalid authentication token" error
- Verify the token format
- Check if the token has expired
- Ensure Clerk keys are correct
3. Permission denied errors
- Verify user roles and permissions in Clerk
- Check the role/permission configuration in
@UseAuth()
Debug Mode
Enable debug logging:
DEBUG=eyjs:authContributing
Contributions are welcome! Please read our Contributing Guide for details.
License
This project is licensed under the MIT License - see the LICENSE file for details.
