Authentication

Lucent provides a complete authentication system with JWT support.

Setup

Enable authentication in your configuration:

// lucent.config.ts
export default defineConfig({
  auth: {
    jwtSecret: process.env.JWT_SECRET,
    jwtExpiry: "7d",
  },
  collections: {
    users: defineCollection({
      /* ... */
    }),
  },
});

User Collection

Your users collection must include specific fields:

export const users = defineCollection({
  name: "users",
  fields: {
    email: { type: "email", required: true, unique: true },
    password: { type: "string", required: true, hidden: true },
    name: { type: "string" },
    role: { type: "select", options: ["admin", "user"], default: "user" },
    // Auth fields
    verified: { type: "boolean", default: false },
    verificationToken: { type: "string", hidden: true },
    resetToken: { type: "string", hidden: true },
    resetExpiry: { type: "datetime", hidden: true },
  },
});

Authentication Methods

Email/Password

// Register
const user = await lucent.auth.register({
  email: "user@example.com",
  password: "securepassword123",
  name: "John Doe",
});

// Login
const { user, token } = await lucent.auth.login({
  email: "user@example.com",
  password: "securepassword123",
});

// Logout (invalidates the current refresh token)
await lucent.auth.logout(token);

// Logout from ALL devices (invalidates every refresh token for this user)
// POST /api/:collection/logout-all
await fetch("/api/users/logout-all", {
  method: "POST",
  headers: { Authorization: `Bearer ${accessToken}` },
});

API Keys

API keys provide a simple, non-rotating credential for programmatic access. They support optional scopes (read, write, admin) that can be used in your access functions to restrict what the key may do.

Managing API keys

// Create a key (POST /api/:collection/api-keys)
const res = await fetch("/api/users/api-keys", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    Authorization: `Bearer ${accessToken}`,
  },
  body: JSON.stringify({
    name: "CI deployment key",
    scopes: ["read", "write"], // optional — omit to grant all operations
    // expiresAt: "2026-01-01T00:00:00Z", // optional ISO-8601 expiry
  }),
});
const { apiKey } = await res.json();
// apiKey.key is only shown once — store it securely

// List your keys (GET /api/:collection/api-keys)
const { apiKeys } = await fetch("/api/users/api-keys", {
  headers: { Authorization: `Bearer ${accessToken}` },
}).then((r) => r.json());

// Revoke a key (DELETE /api/:collection/api-keys/:id)
await fetch(`/api/users/api-keys/${apiKey.id}`, {
  method: "DELETE",
  headers: { Authorization: `Bearer ${accessToken}` },
});

Enforcing scopes in access functions

The scopes array is available on the AuthUser object for requests authenticated with an API key:

export const Posts = defineCollection({
  slug: "posts",
  access: {
    // Only keys with the "write" scope (or regular users) may create posts
    create: ({ user }) => {
      if (!user) return false;
      if (user.scopes) return user.scopes.includes("write") || user.scopes.includes("admin");
      return true; // regular JWT / session user, no scope restriction
    },
  },
  fields: [
    /* ... */
  ],
});

Using the Token

Include the token in API requests:

fetch("/api/posts", {
  headers: {
    Authorization: `Bearer ${token}`,
  },
});

Password Requirements

auth: {
  password: {
    minLength: 8,
    requireUppercase: true,
    requireNumbers: true,
    requireSymbols: true
  }
}

Email Verification

// Send verification email
await lucent.auth.sendVerificationEmail(userId);

// Verify email
await lucent.auth.verifyEmail(token);

Password Reset

// Request password reset
await lucent.auth.requestPasswordReset(email);

// Reset password
await lucent.auth.resetPassword(token, newPassword);