docs/doc/developer/apps/Oauth.mdx
Omi uses an OAuth 2.0-like flow to allow third-party applications to access user data with explicit consent. This ensures users maintain control over their data and what applications can access.
sequenceDiagram
participant App as Your App
participant User as User Browser
participant Omi as Omi Auth Server
participant Firebase as Firebase Auth
App->>User: Redirect to /v1/oauth/authorize
User->>Omi: Visit authorization page
Omi->>Firebase: User logs in (Google/Apple)
Firebase-->>Omi: Firebase ID token
Omi->>Omi: Exchange token for uid
Omi->>User: Redirect to App Home URL
User->>App: ?uid=USER_ID&state=STATE
App->>App: Store uid for API calls
Before implementing OAuth, ensure you have:
<Steps> <Step title="Register Your App" icon="id-card"> Your app must be registered with Omi and have an **App ID** </Step> <Step title="Configure App Home URL" icon="link"> Set your **App Home URL** in your app's settings - this is where users are redirected after authorization </Step> <Step title="HTTPS Required" icon="lock"> Your App Home URL must use HTTPS </Step> </Steps>```
https://api.omi.me/v1/oauth/authorize?app_id=YOUR_APP_ID&state=YOUR_STATE
```
| Parameter | Required | Description |
|-----------|----------|-------------|
| `app_id` | Yes | Your application's unique ID |
| `state` | No | Opaque value for CSRF protection and maintaining state |
<Tip>
Always use the `state` parameter to prevent CSRF attacks. Generate a random string and verify it when the user returns.
</Tip>
1. Logs in with their Firebase credentials (Google or Apple)
2. Reviews the permissions your app is requesting
3. Grants or denies access
**Example permissions shown to users:**
- "Engage in chat conversations with Omi"
- "Access and manage your conversations"
- "Process audio data in real-time"
- "Create new conversations on your behalf"
- "Access and read your stored memories"
```http
POST https://api.omi.me/v1/oauth/token
Content-Type: application/x-www-form-urlencoded
firebase_id_token=FIREBASE_TOKEN&app_id=YOUR_APP_ID&state=YOUR_STATE
```
**Response:**
```json
{
"uid": "USER_UNIQUE_ID",
"redirect_url": "YOUR_APP_HOME_URL",
"state": "YOUR_STATE_IF_PROVIDED"
}
```
<Note>
This step is handled automatically by Omi's authorization page - you don't need to implement this yourself.
</Note>
```
https://your-app.com/callback?uid=USER_UNIQUE_ID&state=YOUR_STATE
```
Your app should:
1. Validate the `state` parameter matches what you sent
2. Store the `uid` for making API calls on behalf of the user
Example implementation for handling the OAuth callback:
<Tabs> <Tab title="Python (FastAPI)" icon="python"> ```python from fastapi import FastAPI, Request, HTTPException from fastapi.responses import RedirectResponse import secretsapp = FastAPI()
# Store state tokens (use Redis in production)
pending_states = {}
@app.get("/start-oauth")
async def start_oauth():
# Generate CSRF token
state = secrets.token_urlsafe(32)
pending_states[state] = True
# Redirect to Omi
return RedirectResponse(
f"https://api.omi.me/v1/oauth/authorize"
f"?app_id=YOUR_APP_ID&state={state}"
)
@app.get("/callback")
async def oauth_callback(uid: str, state: str):
# Validate state
if state not in pending_states:
raise HTTPException(400, "Invalid state parameter")
del pending_states[state]
# Store uid for this user's session
# Now you can make API calls with this uid
return {"message": f"Successfully connected! User ID: {uid}"}
```
const app = express();
const pendingStates = new Map();
app.get('/start-oauth', (req, res) => {
// Generate CSRF token
const state = crypto.randomBytes(32).toString('hex');
pendingStates.set(state, true);
// Redirect to Omi
res.redirect(
`https://api.omi.me/v1/oauth/authorize` +
`?app_id=YOUR_APP_ID&state=${state}`
);
});
app.get('/callback', (req, res) => {
const { uid, state } = req.query;
// Validate state
if (!pendingStates.has(state)) {
return res.status(400).send('Invalid state parameter');
}
pendingStates.delete(state);
// Store uid for this user's session
res.send(`Successfully connected! User ID: ${uid}`);
});
```
When a user completes the OAuth flow, Omi automatically attempts to enable your app for them.
<AccordionGroup> <Accordion title="Enablement Checks" icon="list-check"> Omi performs several checks before enabling:| Check | Description |
|-------|-------------|
| **Privacy** | If app is private, only owner/testers can enable |
| **Setup Completion** | If `setup_completed_url` is configured, it must return `true` |
| **Payment** | If app is paid, user must have active subscription |
If any check fails, the OAuth flow halts and shows an error to the user.
**Request from Omi:**
```
GET https://your-app.com/setup-status?uid=USER_ID
```
**Expected Response:**
```json
{
"is_setup_completed": true
}
```
Return `false` if the user hasn't completed setup yet. Omi will show an appropriate message.
Configure these settings in the Omi developer portal or during app submission:
| Field | Location | Description |
|---|---|---|
| App ID | Auto-generated | Your unique application identifier |
| App Home URL | external_integration.app_home_url | Callback URL after OAuth (HTTPS required) |
| Setup Completed URL | external_integration.setup_completed_url | Optional endpoint to verify user setup |
**Solution:** Verify your App Home URL in the developer portal
**Solution:** Implement proper session/state management with reasonable expiration
**Solution:** Test your endpoint directly and check server logs