Skip to content

Authentication ​

Uranus supports multiple authentication methods to secure agent access.

Overview ​

Authentication layers:

  1. Cloudflare Access - Enterprise SSO integration
  2. Email-Based Access - Role-based agent permissions
  3. API Keys - Service integrations

Cloudflare Access ​

Setup ​

  1. Enable Cloudflare Access for your domain
  2. Configure identity provider (Okta, Google, Azure AD, etc.)
  3. Create an Access application for Uranus
  4. Set the audience tag in wrangler.toml:
toml
[vars]
CF_ACCESS_AUD = "your-access-audience-tag"

JWT Validation ​

The worker validates Cloudflare Access JWTs:

typescript
async function validateAccessJWT(request: Request, env: Env) {
  const jwt = request.headers.get('CF-Access-JWT-Assertion')

  if (!jwt) {
    return null
  }

  // Validate JWT against Cloudflare Access
  const payload = await verifyJWT(jwt, env.CF_ACCESS_AUD)

  return {
    email: payload.email,
    name: payload.name
  }
}

Access Policies ​

Configure Access policies:

  • Allow specific email domains
  • Require MFA
  • Set session duration
  • Define group-based access

Email-Based Access Control ​

Roles ​

RolePermissions
ownerFull access, can delete agent, manage admins
adminFull access, cannot delete agent
viewerRead-only access

Managing Access ​

Add Admin ​

bash
curl -X POST https://your-domain.com/api/agents/{id}/admins \
  -H "Content-Type: application/json" \
  -d '{
    "email": "user@example.com",
    "role": "admin"
  }'

Remove Admin ​

bash
curl -X DELETE https://your-domain.com/api/agents/{id}/admins/{adminId}

List Admins ​

bash
curl https://your-domain.com/api/agents/{id}/admins

Access Check Flow ​

┌─────────────────┐
│  Incoming       │
│  Request        │
└────────┬────────┘
         │
         ▼
┌─────────────────┐     ┌─────────────────┐
│  CF Access      │────▶│  Extract Email  │
│  JWT Present?   │ Yes │  from JWT       │
└────────┬────────┘     └────────┬────────┘
         │ No                    │
         ▼                       ▼
┌─────────────────┐     ┌─────────────────┐
│  Use Default    │     │  Check Agent    │
│  Access         │     │  Access         │
└────────┬────────┘     └────────┬────────┘
         │                       │
         ▼                       ▼
┌─────────────────────────────────────────┐
│            Agent Access Check            │
│                                          │
│  1. Is agent 'default'? → Allow          │
│  2. Is user in agent_admins? → Allow     │
│  3. Otherwise → Deny                     │
└──────────────────────────────────────────┘

Default Agent ​

The default agent has special behavior:

  • Always accessible without authentication
  • Cannot be deleted
  • Used for initial setup
  • Good for public/demo access

Auth Context ​

Frontend ​

Use the AuthContext:

tsx
import { useAuth } from '@/contexts/AuthContext'

function ProfilePage() {
  const { user, isAuthenticated, logout } = useAuth()

  if (!isAuthenticated) {
    return <Navigate to="/login" />
  }

  return (
    <div>
      <p>Welcome, {user.email}</p>
      <button onClick={logout}>Logout</button>
    </div>
  )
}

Protected Routes ​

Wrap routes with ProtectedRoute:

tsx
<Route
  path="/settings"
  element={
    <ProtectedRoute>
      <SettingsPage />
    </ProtectedRoute>
  }
/>

Backend ​

Check authentication in API routes:

typescript
export async function onRequestGet(context: EventContext<Env, string, any>) {
  const { env, request, params } = context

  // Get current user
  const user = await getUser(request, env)

  // Check agent access
  const agentId = params.id
  const hasAccess = await checkAgentAccess(env.DB, agentId, user?.email)

  if (!hasAccess) {
    return new Response('Forbidden', { status: 403 })
  }

  // Continue with request...
}

Service Authentication ​

API Keys ​

Store API keys securely in agent settings:

json
{
  "openai_api_key": "sk-...",
  "anthropic_api_key": "sk-ant-...",
  "telegram_bot_token": "123456:ABC..."
}

Secure Storage ​

API keys are stored in the database:

  • Encrypted at rest (D1 managed)
  • Accessed only by the agent
  • Never exposed in API responses

Using API Keys ​

typescript
// Retrieve from settings
const settings = await getAgentSettings(db, agentId)
const apiKey = settings.openai_api_key

// Use in service call
const response = await fetch('https://api.openai.com/v1/chat/completions', {
  headers: {
    'Authorization': `Bearer ${apiKey}`
  }
})

Security Best Practices ​

1. Enable Cloudflare Access ​

Use Cloudflare Access for production:

  • SSO integration
  • MFA enforcement
  • Session management
  • Audit logging

2. Principle of Least Privilege ​

Assign minimal permissions:

  • Use viewer role for read-only users
  • Reserve owner for trusted admins
  • Regular access reviews

3. Secure API Keys ​

Protect sensitive credentials:

  • Never log API keys
  • Rotate keys regularly
  • Use environment-specific keys

4. Audit Access ​

Monitor authentication events:

  • Track login attempts
  • Review agent access changes
  • Alert on suspicious activity

5. HTTPS Only ​

Always use HTTPS:

  • Cloudflare provides automatic TLS
  • Never expose HTTP endpoints
  • Use secure WebSocket (wss://)

Troubleshooting ​

Access Denied Errors ​

  1. Check user email is in agent_admins
  2. Verify Cloudflare Access JWT is valid
  3. Confirm CF_ACCESS_AUD is correct
  4. Review Access policies

JWT Validation Failures ​

  1. Check token expiration
  2. Verify audience tag
  3. Confirm identity provider config
  4. Review Cloudflare Access logs

Role Issues ​

  1. Verify role in agent_admins table
  2. Check for duplicate entries
  3. Confirm role permissions