| Function | |
|---|---|
signIn(options) | Starts sign-in. Call from a click handler. Returns nothing; results arrive in callbacks |
takeVerifier(state) | PKCE code_verifier for this attempt. Returns it once, then "" |
takeNonce(state) | The nonce sent to Paspo. Returns it once, then "" |
configure({ origin }) | npm build only: set a non-default Paspo origin before the first signIn |
version | SDK version string |
With the CDN build these live on window.Paspo (no configure — the origin comes from the script URL).
| Option | Type | |
|---|---|---|
clientId | string | Required. Your client ID |
redirectUri | string | Required. A registered redirect URI on the same origin as the page |
scope | string | Required. Space-separated scopes, e.g. "openid email" |
fedcm | boolean | false disables the browser's FedCM prompt. Default: used when possible |
onSuccess | (result) => void | Got a code. See result |
onError | (error) => void | Sign-in failed. See errors |
onClose | () => void | The user closed the Paspo window or dismissed the prompt |
Calling signIn again while a window is open closes the old one and starts a new attempt.
interface PaspoSignInResult {
code: string; // one-time, valid 60 s
state: string; // pass to takeVerifier / takeNonce
via?: "fedcm"; // set when the browser prompt issued the code
}
When via is "fedcm", exchange the code without redirect_uri.
If the browser blocks the popup, onSuccess is not called: the tab goes to Paspo and returns to redirectUri?code=…&state=…. takeVerifier(state) works there too — the values are kept in this tab's sessionStorage.
interface PaspoSignInError {
error: string;
error_description: string;
state?: string;
}
error | When | What to do |
|---|---|---|
invalid_request | Missing clientId / redirectUri / scope, an invalid URL, an insecure context (no crypto.subtle) or blocked sessionStorage | Fix the options; serve over HTTPS |
access_denied | The user declined on the consent screen | Let them try again |
| other | Standard OAuth error codes passed through from Paspo, e.g. server_error | Show error_description, let the user retry |
An unknown client_id or an unregistered redirect_uri is never redirected back to your site: Paspo shows the error in its own window. Check both in your client settings.
Errors from the token endpoint (on your server):
error | |
|---|---|
invalid_grant | The code expired (60 s), was already used, or code_verifier / redirect_uri don't match. Start a new sign-in |
invalid_client | Wrong client_id / client_secret |
invalid_request | A required parameter is missing |
unsupported_grant_type | grant_type isn't authorization_code |
| Scope | Claims in id_token | Notes |
|---|---|---|
openid | sub, iss, aud, exp, iat, nonce | Always include it |
profile | name | |
email | email, email_verified | The user picks which address to share |
phone | phone_number, phone_number_verified | The user picks which number to share. phone without email enables the FedCM prompt in Chromium 141+ |
Request at least one of profile, email, phone.
| Claim | Type | |
|---|---|---|
iss | string | https://paspo.id |
sub | string | Stable Paspo user ID. Use it as the account key |
aud | string | Your client_id |
exp, iat | number | Unix seconds |
nonce | string | The value from takeNonce(state) |
name | string | With profile |
email | string | With email — the address the user chose on the consent screen, not necessarily their primary |
email_verified | boolean | With email |
phone_number | string | With phone, E.164, e.g. +77001234567 |
phone_number_verified | boolean | With phone |
| Discovery | GET https://paspo.id/.well-known/openid-configuration |
| Authorize | GET https://paspo.id/oauth/authorize |
| Token | POST https://paspo.id/api/w/v1/oauth/token |
| JWKS | GET https://paspo.id/api/w/v1/oauth/jwks |
| UserInfo | GET https://paspo.id/api/w/v1/oauth/userinfo with Authorization: Bearer <access_token> |
| FedCM config | https://paspo.id/api/w/v1/fedcm/config.json |
The SDK keeps two sessionStorage entries per attempt and removes them when read or when the attempt ends:
paspo.oauth.verifier.<state>paspo.oauth.nonce.<state>No cookies, no localStorage, no tracking.
Paspo.signIn({
clientId: "YOUR_CLIENT_ID",
redirectUri: location.origin + "/auth/paspo/callback",
scope: "openid email",
onSuccess: ({ code, state }) => console.log({ code, verifier: Paspo.takeVerifier(state) }),
});
invalid_grant).The npm package follows semver. The CDN file at https://paspo.id/sdk/paspo.min.js always serves the latest compatible 1.x and is cached for one hour.