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:
- Accept
Authorization: Bearer <token> headers (converts to session cookie internally)
- 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
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: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:Authorization: Bearer <token>headers (converts to session cookie internally)set-auth-tokenresponse 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 pluginIn
buildPluginList(), always include thebearer()plugin frombetter-auth/plugins/bearer:2. CORS configuration
Ensure the server's CORS config includes:
Access-Control-Allow-Headers: AuthorizationAccess-Control-Expose-Headers: set-auth-tokenThe bearer plugin automatically adds
set-auth-tokentoAccess-Control-Expose-Headerson responses, but the server must also allow theAuthorizationrequest header in CORS preflight responses.3.
trustedOriginsconfigurationFor cross-origin deployments,
AuthPluginconfig should support specifying trusted origins:Client Side (already implemented in object-ui)
The
@object-ui/authpackage has been updated in object-ui to:localStorageviaTokenStorageAuthorization: Bearer <token>on all requests viacreateBearerFetchset-auth-tokenresponse headerReferences