npm package: @riligar/auth-elysia
Description: Auth SDK for ElysiaJS with JWT and JWKS
Author: Riligar
Latest version: 1.7.1

# Auth SDK ElysiaJS

Auth SDK for ElysiaJS with JWT and JWKS

## Installation

```bash
bun add @riligar/auth-elysia
```

## 🔑 Environment Variables

| Variable          | Description                       | Default                        |
| ----------------- | --------------------------------- | ------------------------------ |
| `AUTH_SECRET_KEY` | Your RiLiGar Secret Key (sk\_...) | `your-secret-key`              |
| `AUTH_API_URL`    | Auth Manager API URL              | `https://manager.myauth.click` |

```bash
# .env
AUTH_SECRET_KEY=sk_your_secret_key_here
AUTH_API_URL=https://manager.myauth.click
```

## 🚀 Basic Usage

```javascript
import { Elysia } from 'elysia'
import { authPlugin } from '@riligar/auth-elysia'

const app = new Elysia()
    .use(
        authPlugin({
            apiUrl: 'https://manager.myauth.click',
            secretKey: 'your-riligar-secret-key',
        })
    )
    .get('/protected', ({ user, authMeta }) => {
        return {
            message: `Hello ${user?.name}!`,
            verified_locally: authMeta?.verified_locally, // ⚡ Cache hit!
            cached: authMeta?.cached,
        }
    })
    .listen(3000)
```

## 📋 Complete Example

```javascript
import { Elysia } from 'elysia'
import { authPlugin } from '@riligar/auth-elysia'

const app = new Elysia()
    .use(
        authPlugin({
            apiUrl: 'https://manager.myauth.click',
            secretKey: process.env.RILIGAR_SECRET_KEY,
            prefix: '/auth',
            excludePaths: [
                '/', // Homepage
                '/health', // Health check
                '/products', // Product listing
                '/auth/*', // All auth routes
            ],
        })
    )

    // 🌍 PUBLIC ROUTES (in excludePaths)
    .get('/', () => ({ message: 'Welcome to my API!' }))
    .get('/health', () => ({ status: 'ok' }))
    .get('/products', () => ({
        products: [
            { id: 1, name: 'Product 1', price: 100 },
            { id: 2, name: 'Product 2', price: 200 },
        ],
    }))

    // 🔒 PRIVATE ROUTES (automatic - use { user })
    .get('/profile', ({ user }) => {
        // user ALWAYS exists here (token validated)
        return {
            id: user.id,
            name: user.name,
            email: user.email,
        }
    })

    .get('/dashboard', ({ user, authMeta }) => {
        return {
            user: user,
            performance: {
                verified_locally: authMeta?.verified_locally,
                cached: authMeta?.cached,
            },
            data: 'Your private dashboard data...',
        }
    })

    .post('/orders', ({ user, body }) => {
        // user ALWAYS exists here (token validated)
        return {
            message: 'Order created successfully',
            userId: user.id,
            order: body,
        }
    })

    .get('/admin', ({ user }) => {
        // Additional role verification
        if (user.role !== 'admin') {
            return { error: 'Admin access required' }
        }
        return {
            message: 'Admin panel',
            adminData: 'Secret admin data',
        }
    })

    .listen(3000)

console.log('🚀 Server running on http://localhost:3000')
console.log('🌍 Public routes: /, /health, /products')
console.log('🔒 Private routes: /profile, /dashboard, /orders, /admin')
```

## ⚙️ Configuration

```javascript
const config = {
    prefix: '/auth', // Auth routes prefix
    apiUrl: 'https://manager.myauth.click', // Auth Service URL
    secretKey: 'se_abc123...', // Your RiLiGar Secret Key
    cookieName: 'auth-token', // Cookie name
    excludePaths: ['/auth/login', '/auth/register'], // Public routes
    cookieOptions: {
        httpOnly: true,
        secure: process.env.NODE_ENV === 'production',
        sameSite: 'lax',
        maxAge: 604800, // 7 days (same as JWT TTL)
    },
    onUnauthorized: set => {
        set.status = 401
        return { error: 'Access denied' }
    },
}
```

## 🛡️ Available Routes

-   `POST /auth/login` - Login with email/password
-   `POST /auth/register` - User registration
-   `POST /auth/logout` - Logout (local + remote)
-   `GET /auth/session` - Check current session
-   `GET /auth/me` - User data

## 👤 User Object

The `user` object is available in all protected routes and contains:

```typescript
interface User {
    id: string // Unique user ID (UUID)
    email: string // User email
    name: string // User display name
    image?: string // Avatar URL (optional)
    emailVerified: boolean // Email verification status
    applicationId?: string // Application ID (if multi-tenant)
    role?: string // User role from JWT claims
    iat: number // Issued at (Unix timestamp)
    exp: number // Expiration (Unix timestamp)
    iss: string // Issuer (e.g., 'riligar-auth')
    sub: string // Subject (user ID)
}
```

### authMeta Object

Performance metadata available alongside user:

```typescript
interface AuthMeta {
    verified_locally: boolean // True if JWT was verified locally via JWKS
    cached: boolean // True if JWKS was retrieved from cache
}
```

## ⚡ Performance Features

✅ **Local JWKS Verification**: Public keys cache (1h TTL)  
✅ **Multi-Algorithm Support**: HS256 (HMAC) e RS256 (RSA)  
✅ **Native JWT**: Using Bun's Web Crypto API  
✅ **Smart Fallback**: Local → Remote when needed  
✅ **Zero Latency**: Valid tokens verified instantly

## 🔧 How It Works

1. **First attempt**: Local verification with cached JWKS
2. **Cache miss**: Fetch JWKS from `/.well-known/jwks.json`
3. **Fallback**: Remote verification if JWKS fails
4. **Performance**: ~99% of tokens verified locally

## 🔐 Supported Algorithms

-   **HS256**: HMAC with SHA-256 (symmetric key)
-   **RS256**: RSA with SHA-256 (asymmetric key via JWKS)

The plugin automatically detects the JWT algorithm and uses the appropriate verification method.

## 🧪 Testing

```bash
# Register a user
curl -X POST http://localhost:3000/auth/register \
  -H "Content-Type: application/json" \
  -d '{"email":"john@example.com","password":"123456","name":"John Doe"}'

# Login
curl -X POST http://localhost:3000/auth/login \
  -H "Content-Type: application/json" \
  -d '{"email":"john@example.com","password":"123456"}'

# Access protected route (use token from login)
curl http://localhost:3000/profile \
  -H "Authorization: Bearer YOUR_TOKEN_HERE"

# Check session
curl http://localhost:3000/auth/session \
  -H "Authorization: Bearer YOUR_TOKEN_HERE"
```

## Build

```bash
bun run build
```

## License

MIT