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 → tokensCode (SDK-based)
npm i git+https://github.com/Copark-Dev/cp-auth-sdk.git#v0.5.2Step 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=....