Skip to navigation

OAuth

With OAuth, users sign in to Whop themselves through a sign-in page or an iOS webview. Your app receives Whop user tokens that can authenticate embedded chat and act on behalf of the signed-in user.

Use OAuth when your app needs access to the user’s Whop account, or when you do not want to mint company-scoped user tokens from your own backend.

Setup

Use the Create App endpoint to create an OAuth app programmatically:

import Whop from "@whop/sdk";
const client = new Whop({ apiKey: process.env.WHOP_API_KEY });
const app = await client.apps.create({
name: "My App",
redirect_uris: [
"http://localhost:3000/api/auth/callback/whop",
"https://myapp.com/api/auth/callback/whop"
],
});
console.log(app.id); // App ID
console.log(app.client_secret); // Client Secret

Update redirect URIs later with the Update App endpoint.

Required scopes

Your OAuth configuration should include these scopes:

ScopePurpose
openid, profile, emailBasic profile info
chat:message:create, chat:readChannels
dms:read, dms:message:manage, dms:channel:manageDirect messages
support_chat:read, support_chat:message:createSupport chats

Web token endpoint

Your server needs to provide a token endpoint that returns a valid OAuth token with the required scopes. The React and vanilla JavaScript chat elements call this function whenever they need to authenticate.

async function getToken() {
const response = await fetch("/api/token");
const data = await response.json();
return data.token;
}

See the OAuth guide for implementing the server-side token exchange.

SDK-managed OAuth on iOS

Call configureWithOAuth on app launch. The SDK handles the entire flow: showing a sign-in webview, obtaining tokens, and refreshing them automatically.

.task {
await WhopSDK.configureWithOAuth(
appId: "app_XXXXXXXXXXXXXX",
scopes: [
"openid", "profile", "email",
"chat:message:create", "chat:read",
"dms:read", "dms:message:manage", "dms:channel:manage",
"support_chat:read", "support_chat:message:create",
]
)
}

By default, the SDK uses your bundle identifier for the redirect URI (com.yourapp.bundle://oauth/callback). You can customize this:

await WhopSDK.configureWithOAuth(
appId: "app_XXXXXXXXXXXXXX",
redirectUri: "myapp://auth/callback",
scopes: [
"openid", "profile", "email",
"chat:message:create", "chat:read",
"dms:read", "dms:message:manage", "dms:channel:manage",
"support_chat:read", "support_chat:message:create",
]
)

Make sure the redirect URI matches what you configured in the Whop Dashboard > Developer > App > OAuth.

When a user navigates to a chat view, the OAuth flow is triggered automatically if they’re not already authenticated. You can also trigger sign-in and sign-out manually:

// Sign in
try await WhopSDK.signIn()
// Sign out
WhopSDK.signOut()

Tracking authentication state

Use the .whopAuthState modifier to reactively track whether the user is signed in:

struct ChatView: View {
@State private var isAuthenticated = false
var body: some View {
VStack {
if isAuthenticated {
Text("Signed In")
} else {
Text("Not Signed In")
}
}
.whopAuthState($isAuthenticated)
}
}

Pre-filling tokens

If you already have the user’s Whop tokens from another source, such as a web OAuth flow or tokens synced from your backend, you can pre-fill them to skip the sign-in webview on first launch. This is optional and only relevant if your users have already authenticated with Whop elsewhere.

let tokens = await myBackend.getWhopTokens(for: currentUser)
try await WhopSDK.preSignIn(
accessToken: tokens.accessToken,
refreshToken: tokens.refreshToken
)

The SDK extracts the token expiration from the JWT and handles refresh automatically. If the pre-filled tokens expire and can’t be refreshed, the normal OAuth flow kicks in.

Next steps