Skip to content

Conversation

@standujar
Copy link
Collaborator

@standujar standujar commented Dec 3, 2025

Relates to

  • Data isolation / multi-entity support
  • External JWT provider integration (Privy, Auth0, Clerk, Supabase, Google, Embbeded)

Risks

Low

  • Requires ENABLE_DATA_ISOLATION=true to activate JWT auth mode

Background

What does this PR do?

Implements a complete JWT authentication system for ElizaOS with support for multiple verification strategies:

  1. JWT Verifier Factory - Priority-based verifier selection:

    • Ed25519 (highest priority) - For self-signed JWTs with Ed25519 keys
    • JWKS (medium priority) - For external providers (Auth0, Clerk, Privy, Supabase, Google)
    • Secret (lowest priority) - For simple HS256 symmetric key verification
  2. Entity ID derivation from JWT sub claim:

    • entityId = stringToUuid(payload.sub)
    • Compatible with ANY JWT provider since sub is a standard claim
    • No custom claims needed in external JWTs
  3. Dual authentication modes:

    • ENABLE_DATA_ISOLATION=true → JWT authentication required
    • ENABLE_DATA_ISOLATION=false → X-Entity-Id header (legacy mode)
  4. Internal service bypass - Process-local UUID secret for service-to-service calls

  5. Credentials-based auth endpoints (/api/auth/*) - only in custom - JWT-SECRET mode:

    • POST /register - User registration with bcrypt password hashing
    • POST /login - User login with JWT generation
    • POST /refresh - Token refresh
    • GET /me - Current user info
  6. **Client UI default implementation using self mode (Secret)

What kind of change is this?

Features (non-breaking change which adds functionality)

Architecture

┌─────────────────────────────────────────────────────────────────┐
│                    JWT Verification Flow                         │
├─────────────────────────────────────────────────────────────────┤
│  Request with Bearer token                                       │
│       ↓                                                          │
│  JWTVerifierFactory.create()                                     │
│       ↓                                                          │
│  Priority: Ed25519 > JWKS > Secret > Disabled                   │
│       ↓                                                          │
│  verifier.verify(token)                                          │
│       ↓                                                          │
│  Extract payload.sub                                             │
│       ↓                                                          │
│  entityId = stringToUuid(sub)  ← Derived, NOT stored in JWT     │
│       ↓                                                          │
│  req.entityId = entityId                                         │
└─────────────────────────────────────────────────────────────────┘

Environment Variables

Variable Description Example
ENABLE_DATA_ISOLATION Enable JWT auth mode true
JWT_SECRET (optional) HS256 symmetric secret your-secret-key
JWT_PUBLIC_KEY_ED25519 (optional) Ed25519 public key (base64) MCowBQYDK2Vw...
JWT_JWKS_URI (optional) JWKS endpoint URL https://auth0.com/.well-known/jwks.json
JWT_ISSUER_WHITELIST (optional) Allowed issuers (comma-separated) https://auth0.com/,https://clerk.dev

Documentation changes needed?

Yes - Documentation should be added for:

  • Environment variable configuration
  • External provider setup (Auth0, Clerk, Privy examples)

Testing

Where should a reviewer start?

  1. packages/server/src/services/jwt-verifiers/factory.ts - Core factory logic
  2. packages/server/src/middleware/jwtMiddleware.ts - HTTP middleware
  3. packages/server/src/socketio/index.ts - SocketIO authentication

Detailed testing steps

Unit Tests:

cd packages/server
bun run test:unit

Integration Tests:

cd packages/server
bun run test:integration

Results: 489 unit tests pass, 6 integration test files pass

Manual Testing

  1. Test with JWT_SECRET (HS256):
ENABLE_DATA_ISOLATION=true JWT_SECRET=test-secret bun run dev
  1. Register a user:
curl -X POST http://localhost:3000/api/auth/register \
  -H "Content-Type: application/json" \
  -d '{"email":"[email protected]","username":"testuser","password":"password123"}'
  1. Use returned token:
curl http://localhost:3000/api/agents \
  -H "Authorization: Bearer <token>"

External Provider Compatibility

Tested JWT formats:

  • Auth0: sub: "auth0|1234567890"
  • Clerk: sub: "user_2abcdefgh123456"
  • Google: sub: "1234567890" with email, email_verified
  • Supabase: sub: "uuid" with role: "authenticated"
  • Privy: sub: "did:privy:..."

All providers work because we only require the standard sub claim.

Next Idea Steps: Access Control Layer (ACL)

The next phase will add access control on agents and rooms:

Agents:

  • Each user can create their own agents (ownerId = entityId)
  • Visibility: public or private
  • Private = only the owner can chat with it
  • Public = everyone can chat, but only the owner can modify/delete

Rooms:

  • Each room has an owner
    Only the owner can:
  • Delete the room (DELETE /rooms/:id)
  • Clear message history (DELETE /rooms/:id/messages)
  • Change visibility

This will enable true multi-tenant mode where each user manages their resources in isolation.

@graphite-app
Copy link

graphite-app bot commented Dec 3, 2025

How to use the Graphite Merge Queue

Add either label to this PR to merge it via the merge queue:

  • merge-queue - adds this PR to the back of the merge queue
  • merge-queue-hotfix - for urgent hot fixes, skip the queue and merge this PR next

You must have a Graphite account in order to use the merge queue. Sign up using this link.

An organization admin has enabled the Graphite Merge Queue in this repository.

Please do not merge from GitHub as this will restart CI on PRs being processed by the merge queue.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 3, 2025

Important

Review skipped

Auto reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/jwt-auth

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@claude

This comment was marked as outdated.

@claude

This comment was marked as duplicate.

@standujar standujar self-assigned this Dec 4, 2025
@claude

This comment was marked as duplicate.

@claude

This comment was marked as outdated.

@claude
Copy link
Contributor

claude bot commented Dec 8, 2025

Claude finished @standujar's task —— View job


PR Review: JWT Authentication Implementation

Review Checklist:

  • Security audit (hardcoded keys, injection vulnerabilities)
  • Test coverage analysis
  • TypeScript usage validation
  • ElizaOS patterns compliance
  • Breaking changes assessment
  • Code quality review

Findings:

CRITICAL: Rate limiting addressed but /me endpoint still lacks rate limiting → Fix: Add authRateLimit middleware to /me endpoint in packages/server/src/api/auth/credentials.ts:180

⚠️ IMPORTANT: Test secrets used in production code paths → Fix: Ensure test JWT secrets are only used in test environment checks in packages/server/src/__tests__/integration/jwt-workflow.test.ts

⚠️ IMPORTANT: Missing input validation on JWT payload fields → Fix: Add validation for username and email claims in JWT payload before using them in packages/server/src/api/auth/credentials.ts:158-160

💡 SUGGESTION: Inconsistent TypeScript typing → Consider: Replace any types with proper interfaces in packages/server/src/middleware/entity-auth.ts:13 and packages/server/src/api/auth/credentials.ts:91

Security Assessment: ✅ GOOD

  • No hardcoded secrets in production code
  • Proper bcrypt password hashing (salt rounds: 10)
  • JWT verification follows security best practices
  • Localhost + secret validation for internal services
  • Input validation on registration/login endpoints
  • Rate limiting implemented for auth endpoints (except /me)

Test Coverage: ✅ EXCELLENT

  • 39 test files with comprehensive coverage
  • Unit tests for all JWT verifier implementations
  • Integration tests for complete auth workflows
  • Proper use of bun test throughout
  • Test utilities follow functional patterns

Architecture: ✅ FOLLOWS ELIZAOS PATTERNS

  • Correct use of @elizaos/core imports
  • Functional approach with factory patterns
  • Proper error handling with structured logging
  • No circular dependencies detected
  • Uses ElizaOS UUID system correctly

Breaking Changes: ✅ NON-BREAKING

  • Feature is opt-in with ENABLE_DATA_ISOLATION=true
  • Legacy X-Entity-Id header mode preserved
  • Backwards compatible factory methods provided

@claude
Copy link
Contributor

claude bot commented Dec 9, 2025

Claude finished @standujar's task —— View job


PR Review: JWT Authentication Implementation

Review Checklist:

  • Security audit (hardcoded keys, injection vulnerabilities)
  • Test coverage analysis
  • TypeScript usage validation
  • ElizaOS patterns compliance
  • Breaking changes assessment
  • Code quality review

Findings:

CRITICAL: Rate limiting addressed but /me endpoint still lacks rate limiting → Fix: Add authRateLimit middleware to /me endpoint in packages/server/src/api/auth/credentials.ts:180

⚠️ IMPORTANT: Test secrets used in production code paths → Fix: Ensure test JWT secrets are only used in test environment checks in packages/server/src/__tests__/integration/jwt-workflow.test.ts

⚠️ IMPORTANT: Missing input validation on JWT payload fields → Fix: Add validation for username and email claims in JWT payload before using them in packages/server/src/api/auth/credentials.ts:158-160

💡 SUGGESTION: Inconsistent TypeScript typing → Consider: Replace any types with proper interfaces in packages/server/src/middleware/entity-auth.ts:13 and packages/server/src/api/auth/credentials.ts:91

Security Assessment: ✅ GOOD

  • No hardcoded secrets in production code
  • Proper bcrypt password hashing (salt rounds: 10)
  • JWT verification follows security best practices
  • Localhost + secret validation for internal services
  • Input validation on registration/login endpoints
  • Rate limiting implemented for auth endpoints (except /me)

Test Coverage: ✅ EXCELLENT

  • 39 test files with comprehensive coverage
  • Unit tests for all JWT verifier implementations
  • Integration tests for complete auth workflows
  • Proper use of bun test throughout
  • Test utilities follow functional patterns

Architecture: ✅ FOLLOWS ELIZAOS PATTERNS

  • Correct use of @elizaos/core imports
  • Functional approach with factory patterns
  • Proper error handling with structured logging
  • No circular dependencies detected
  • Uses ElizaOS UUID system correctly

Breaking Changes: ✅ NON-BREAKING

  • Feature is opt-in with ENABLE_DATA_ISOLATION=true
  • Legacy X-Entity-Id header mode preserved
  • Backwards compatible factory methods provided

Copy link
Collaborator

@0xbbjoker 0xbbjoker left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants