Skip to content

plugin-auth: Add bearer() plugin support for cross-origin token-based auth #1172

@hotlong

Description

@hotlong

Problem

When the frontend (e.g. localhost:5173) connects to an API on a different origin (e.g. demo.objectstack.ai), session cookies are blocked by the browser due to third-party cookie restrictions. This means:

  • Users can sign in successfully
  • But refreshing the page loses the session (cookie not sent cross-origin)
  • Mobile clients (iOS/Android) also cannot use cookie-based auth

This is the standard behavior of modern browsers (Chrome, Safari, Firefox all block third-party cookies).

Solution

Add the better-auth bearer() server-side plugin to @objectstack/plugin-auth, so the server can:

  1. Accept Authorization: Bearer <token> headers (converts to session cookie internally)
  2. Expose the session token via set-auth-token response header (so the client can store it)

This is how Salesforce, Notion, Supabase, and all mobile apps handle auth — token-based, not cookie-based.

Required Changes

1. @objectstack/plugin-auth — Add bearer plugin

In buildPluginList(), always include the bearer() plugin from better-auth/plugins/bearer:

import { bearer } from 'better-auth/plugins/bearer';

buildPluginList() {
  const plugins = [
    bearer(), // Always enabled — supports cross-origin and mobile clients
  ];
  // ... existing organization, twoFactor, magicLink plugins
  return plugins;
}

2. CORS configuration

Ensure the server's CORS config includes:

  • Access-Control-Allow-Headers: Authorization
  • Access-Control-Expose-Headers: set-auth-token

The bearer plugin automatically adds set-auth-token to Access-Control-Expose-Headers on responses, but the server must also allow the Authorization request header in CORS preflight responses.

3. trustedOrigins configuration

For cross-origin deployments, AuthPlugin config should support specifying trusted origins:

new AuthPlugin({
  secret: '...',
  trustedOrigins: ['http://localhost:5173', 'https://console.example.com'],
})

Client Side (already implemented in object-ui)

The @object-ui/auth package has been updated in object-ui to:

  • Store session tokens in localStorage via TokenStorage
  • Inject Authorization: Bearer <token> on all requests via createBearerFetch
  • Capture rotated tokens from set-auth-token response header
  • Clear tokens on sign-out

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions