CP-Hosted Login Page

When you don't want to build your own login UI, redirect the user to the auth.cp-platform.com login page. This is the smallest amount of integration code.

Flow

[User] → clicks "Sign in with CP"
       ↓
[App] window.location = "https://auth.cp-platform.com/oauth/login?client_id=...&redirect_uri=..."
       ↓
[CP-Auth] login page (Google / Kakao / Email buttons)
       ↓
[User] completes authentication
       ↓
[CP-Auth] redirect → your-app.com/auth/callback?code=...&state=...
       ↓
[App BE] POST /oauth/token → tokens

Code (SDK-based)

npm i git+https://github.com/Copark-Dev/cp-auth-sdk.git#v0.5.2

Step 1 — login button

import { CpAuthClient } from "@cp-platform/auth-sdk";
 
const cp = new CpAuthClient({
  authUrl: "https://auth.cp-platform.com",
  productOrigin: "https://your-app.com",
  clientId: "cp_xxxxx",
  redirectUri: "https://your-app.com/auth/callback",
});
 
<button onClick={() => cp.startOAuth("google")}>Sign in with CP</button>

startOAuth generates & stores the PKCE code-verifier, then redirects to auth.cp-platform.com.

Step 2 — callback page

import { CpAuthClient } from "@cp-platform/auth-sdk";
 
const cp = new CpAuthClient({ /* same config */ });
 
// at /auth/callback?code=...&state=...
const { code, codeVerifier } = cp.consumeCallback(window.location.search);
 
await fetch("/api/auth/token", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ code, codeVerifier }),
});
window.location.href = "/dashboard";

Step 3 — backend token exchange

Use CpServerClient from @cp-platform/auth-sdk/server. Same code as Self-hosted Step 2.

Popup variant

If you prefer a popup, switch redirectUri to the popup callback URL:

const cp = new CpAuthClient({
  // ...
  redirectUri: "https://cp-platform.com/oauth/popup-callback",
});
const { code, codeVerifier } = await cp.startOAuthPopup("google");

Backend exchange uses the same redirectUri. Full signature: SDK Reference.

Troubleshooting

invalid_request: redirect_uri not registered

→ The redirect_uri is missing from the console allowlist. Add it.

Callback page renders blank

→ Check that cp.consumeCallback(window.location.search) is invoked. The URL must contain ?code=...&state=....