Official plugin — Facebook Login via Graph API with conservative email handling.
Facebook Login is OAuth2 against the Graph API, and its trust story is the
simplest one in oauth(): the platform offers no verification signal to
apps, so emails from Facebook are treated as unverified — always.
The one rule
Treat every Facebook-provided address as unverified. The flow provisions new accounts with them but refuses to let them claim accounts that already exist.
Quick start
Create an app
Meta for Developers → Create App → Authentication. Under Facebook Login
→ Settings, add https://app.example.com/auth/oauth/callback/facebook as a
Valid OAuth Redirect URI.
Plug it
import { oke } from "okengine";
import { oauth } from "okengine/plugins";
export const app = oke({
name: "shop",
env: "dev",
gate: { auth: {} },
}).plug(
oauth({
baseUrl: "https://app.example.com",
providers: {
facebook: { enabled: true },
},
}),
);Set the client secret
# .env.local
OAUTH_FACEBOOK_CLIENT_SECRET=...How identity works
| Aspect | Behavior |
|---|---|
| Authorize | www.facebook.com/v21.0/dialog/oauth |
| Token exchange | graph.facebook.com/v21.0/oauth/access_token |
| Profile | GET /me?fields=id,name,email (the id is the subject) |
| present when the user has one; phone-only accounts have none | |
| Email trust | always unverified — no trustworthy provider signal exists |
Consequence: an attacker completing Facebook login with your email gets
email_in_use, not your session. This exact scenario is the takeover class
the trust matrix closes.
Default scopes: email, public_profile.
Options
| Option | Type | Default | Meaning |
|---|---|---|---|
enabled | boolean | false | Turn the provider on |
clientId | string | Vault/env* | \*OAUTH_FACEBOOK_CLIENT_ID (App ID) |
redirectUri | string | {baseUrl}…/facebook | Exact registered URI |
scopes | string[] | driver defaults | Extra scopes |
storeProviderTokens | boolean | false | Keep tokens in Vault |
Surfaces
| Flow | Path |
|---|---|
| Start | POST /auth/oauth/facebook/start |
| Callback | GET+POST /auth/oauth/callback/facebook |
| Link | POST /auth/oauth/facebook/link |
Troubleshooting
The URI is not on the Valid OAuth Redirect URIs list, or the app is in development mode and the user lacks a role. Byte-exact matching applies.
The user declined the email permission or has none on file. The flow proceeds without an address — same behavior as Discord phone-only accounts.
The app secret was rotated or the code was replayed. Codes are single-use;
restart from /start.