Intro

Use Whop OAuth to authenticate users in your web or iOS app.

This guide only covers the basic steps to implement Whop OAuth and does not cover best practices regarding the OAuth2 protocol. It is recommended to use a library to handle the OAuth2 flow.

We are going to release a guide on how to implement Whop OAuth with auth.js soon.

Step 1: Create a Whop App and obtain secrets

  1. Go to the Whop Dashboard and create a new app or select an existing one.

  2. Add a redirect uri in your apps OAuth settings

    To test your app locally you can add a redirect uri on http://localhost:{PORT} but it is recommended to use https for production.

  3. Copy the app id and api key and set them in your environment variables.

    Keep in mind that the api key is a secret and should not be shared with anyone. The app id is public and can be shared with anyone.

    WHOP_APP_ID=your-app-id
    WHOP_API_KEY=your-api-key

Step 2: Initiate the OAuth flow

Setup the OAuth flow

Start off by creating a route that will be hit by the user when they click the Login with Whop button:

/api/oauth/init/route.ts
export function GET(request: Request) {
  const url = new URL(request.url);
  const next = url.searchParams.get("next") ?? "/home";

  const oAuthUrl = `https://whop.com/oauth/`;

  // this is the app id you obtained in step 1.3
  oAuthUrl.searchParams.set("client_id", process.env.WHOP_APP_ID);
  // This has to be defined in the redirect uris outlined in step 1.2
  oAuthUrl.searchParams.set(
    "redirect_uri",
    "http://localhost:3000/api/oauth/callback"
  );
  oAuthUrl.searchParams.set("response_type", "code");
  oAuthUrl.searchParams.set("scope", "read_user");

  // The state is used to restore the `next` parameter after the user lands on the callback route.
  // Note: This is not a secure way to store the state and for demonstration purposes only.
  const state = crypto.randomUUID();
  oAuthUrl.searchParams.set("state", state);

  return Response.redirect(oAuthUrl.toString(), {
    headers: {
      "Set-Cookie": `oauth-state.${state}=${encodeURIComponent(
        next
      )}; Path=/; HttpOnly; Secure; SameSite=Lax; Max-Age=3600`,
    },
  });
}

You can specify multiple scopes by separating them with a space.

Read more about available scopes here.

Adding the Login with Whop button

Now continue by adding a link to your app that will initiate the Login with Whop flow:

<a href="/api/oauth/init?next=/home">Login with Whop</a>

Upon clicking the link the user will be redirected to the Whop OAuth page and is prompted to authorize your app.

Step 3: Exchange the code for a token

Upon successful authorization the user will be redirected to the redirect uri you specified in the query parameters with a code query parameter,

/api/oauth/callback/route.ts
export function GET(request: Request) {
  const url = new URL(request.url);
  const code = url.searchParams.get("code");
  const state = url.searchParams.get("state");

  if (!code) {
    // redirect to error page
    return Response.redirect("/oauth/error?error=missing_code");
  }

  if (!state) {
    // redirect to error page
    return Response.redirect("/oauth/error?error=missing_state");
  }

  const stateCookie = request.headers
    .get("Cookie")
    ?.split(";")
    .find((cookie) => cookie.trim().startsWith(`oauth-state.${state}=`));

  if (!stateCookie) {
    // redirect to error page
    return Response.redirect("/oauth/error?error=invalid_state");
  }

  // exchange the code for a token
  const response = await fetch("https://api.whop.com/oauth/token", {
    method: "POST",
    body: JSON.stringify({
      code,
      client_id: process.env.WHOP_APP_ID,
      client_secret: process.env.WHOP_API_KEY,
      grant_type: "authorization_code",
      redirect_uri: "http://localhost:3000/api/oauth/callback",
    }),
    headers: {
      "Content-Type": "application/json",
    },
  });

  if (!response.ok) {
    // redirect to error page
    return Response.redirect("/oauth/error");
  }

  const { access_token } = await response.json();

  // Restore the `next` parameter from the state cookie set in the previous step.
  const next = decodeURIComponent(stateCookie.split("=")[1]);
  const nextUrl = new URL(next, "http://localhost:3000");

  // This is an example, you should not store the plain user auth token in a cookie in production.

  // After setting the cookie you can now identify the user by reading the cookie when the user visits your website.
  return Response.redirect(nextUrl.toString(), {
    headers: {
      "Set-Cookie": `whop_access_token=${access_token}; Path=/; HttpOnly; Secure; SameSite=Lax; Max-Age=3600`,
    },
  });
}

Implementing with authentication frameworks

Auth.js (coming soon)

We will release an extensive guide on how to implement Whop OAuth with auth.js soon.