Feature: Authentication (OAuth)
Relevant source files
The following files were used as context for generating this wiki page:
The authentication system provides user sign-in capabilities through an external OAuth 2.0 provider. It is designed to support both web and native mobile (iOS/Android) platforms, employing different strategies for session management on each. For web, it uses secure, HTTP-only cookies, while for native mobile, it uses bearer tokens stored securely on the device.
The system is responsible for the entire authentication lifecycle, including initiating the login flow, handling the OAuth callback, exchanging the authorization code for tokens, fetching user information, creating and verifying local session tokens (JWTs), and synchronizing user data with a local database. It also provides mechanisms for authenticating API requests and handling user logout.
Architecture Overview
The authentication architecture involves three main participants: the client application (React Native for mobile, React for web), the backend API server (Express), and the external Manus OAuth provider. The backend server acts as a crucial intermediary, handling token exchanges and session management to keep client secrets and access tokens off the client.
This diagram illustrates the high-level interaction between the components.
Configuration
Authentication behavior is configured through environment variables, which are accessed via constants.
| Variable | Description | Source File |
|---|---|---|
EXPO_PUBLIC_OAUTH_PORTAL_URL | The base URL for the external OAuth provider's authentication portal. | constants/oauth.ts:9 |
EXPO_PUBLIC_OAUTH_SERVER_URL | The base URL for the external OAuth provider's API server. | constants/oauth.ts:10 |
EXPO_PUBLIC_APP_ID | The application's unique ID registered with the OAuth provider. | constants/oauth.ts:11 |
EXPO_PUBLIC_API_BASE_URL | The base URL for this application's own backend server. | constants/oauth.ts:13 |
COOKIE_NAME | The name of the session cookie. Defined as manus_session. | server/_core/oauth.ts:1 |
COOKIE_SECRET | A secret key used to sign and verify session JWTs. | server/_core/sdk.ts:131 |
The application also dynamically determines the OAuth redirectUri based on the platform. For native, it uses a deep link scheme, while for web, it points to a server-side API endpoint.
Sources: constants/oauth.ts:58-71
Authentication Flows
The system implements distinct but related authentication flows for web and native mobile platforms.
Web Authentication Flow
The web flow uses a server-side callback and HTTP-only cookies for session management, which is a secure standard for web applications.
This diagram shows the web authentication sequence, where the server handles all token exchanges and sets a session cookie.
Sources: server/_core/oauth.ts:63-90, constants/oauth.ts:61-64
Native Mobile Authentication Flow
The native flow uses a deep link to return to the app and a separate API endpoint to exchange the authorization code for a session token, which is then stored on the device.
This diagram shows the native mobile flow, where the app receives a session token via a JSON response and stores it locally.
Sources: server/_core/oauth.ts:92-123, app/oauth/callback.tsx:162-184, lib/_core/api.ts:100-119, constants/oauth.ts:65-70
Server-Side Components
The backend is responsible for all secure interactions with the OAuth provider and for session management.
API Endpoints
The following endpoints are registered in server/_core/oauth.ts to handle the authentication process.
| Endpoint | Method | Platform | Description |
|---|---|---|---|
/api/oauth/callback | GET | Web | Handles the OAuth callback for web. Exchanges the code, syncs the user, creates a session JWT, and sets it in an HTTP-only cookie before redirecting to the frontend. |
/api/oauth/mobile | GET | Mobile | Handles the code exchange for mobile. Exchanges the code, syncs the user, creates a session JWT, and returns it along with user data in a JSON response. |
/api/auth/me | GET | Both | Fetches the currently authenticated user's information. Works with both cookie (web) and Authorization: Bearer token (mobile). |
/api/auth/logout | POST | Both | Clears the session cookie on the server, effectively logging the user out. |
/api/auth/session | POST | Web | Establishes a session cookie from a provided bearer token. Used in iframe scenarios. |
Sources: server/_core/oauth.ts:63-189
SDK Service (SDKServer)
The SDKServer class in server/_core/sdk.ts encapsulates all logic for interacting with the external OAuth provider and managing internal sessions.
This diagram shows the key methods of the SDKServer class and its composition of OAuthService.
Sources: server/_core/sdk.ts:71-247
Key methods include:
exchangeCodeForToken: Exchanges an authorization code for an access token.getUserInfo: Fetches user details from the OAuth provider using an access token.createSessionToken: Creates a signed JWT containing the user'sopenId,appId, andname. This token serves as the application's session token.verifySession: Verifies the signature and validity of a session JWT.authenticateRequest: Middleware-like function that authenticates an incoming request by checking for a valid session token (from a cookie or bearer token), and fetches the corresponding user from the database. It also automatically syncs the user from the OAuth provider if they don't exist locally.
User Synchronization
When a user signs in, the syncUser function is called to create or update their record in the local users database table. This ensures that the application has a local, up-to-date copy of essential user information.
Sources: server/_core/oauth.ts:19-39, drizzle/schema.ts:6-21
Client-Side Components
The client-side handles the user-facing parts of authentication, state management, and secure token storage.
Callback Screen (app/oauth/callback.tsx)
This React component is the designated redirect target after a user authenticates with the OAuth provider. Its primary responsibilities are:
- Parsing
code,state, anderrorparameters from the incoming URL. - For mobile, calling the
exchangeOAuthCodeAPI function to trade thecodefor a session token. - Storing the received session token and user information using
Auth.setSessionTokenandAuth.setUserInfo. - Redirecting the user to the main application interface (e.g.,
/(tabs)) upon success. - Displaying processing, success, or error messages to the user.
Sources: app/oauth/callback.tsx
Authentication Hook (useAuth)
The useAuth hook is the primary interface for components to access authentication state. It provides:
user: The current user object ornull.isAuthenticated: A boolean indicating if the user is logged in.loading: A boolean indicating if the authentication status is being checked.logout: A function to log the user out.
The hook implements platform-specific logic:
- Web: It calls the
/api/auth/meendpoint to fetch the user, relying on the browser's automatic cookie handling. - Native: It checks for a session token in
SecureStore. If a token exists, it retrieves the cached user info.
Sources: hooks/use-auth.ts
Secure Storage (lib/_core/auth.ts)
This module abstracts the storage of the session token and user information.
- On native platforms, it uses
expo-secure-storeto securely store data. - On the web, it uses
localStorageto cache user info (the session itself is managed by server-set cookies).
Key functions:
setSessionToken(token): Stores the session token (native only).getSessionToken(): Retrieves the session token (native only).removeSessionToken(): Deletes the session token (native only).setUserInfo(user): Caches the user object.getUserInfo(): Retrieves the cached user object.clearUserInfo(): Deletes the cached user object.
Sources: lib/_core/auth.ts, constants/oauth.ts:48-49
Data Models & Schemas
User Database Schema
The users table stores user information synchronized from the OAuth provider.
Sources: drizzle/schema.ts:6-21
Session Token Payload
The session token created by the server is a JWT with the following payload structure.
type SessionPayload = {
openId: string;
appId: string;
name: string;
};
Sources: server/_core/sdk.ts:29-33