Authentication
Google sign-in, cookies, refresh rotation, and logout
PeridotID authentication is cookie-based. After a successful Google sign-in the API
sets two HttpOnly cookies on your domain.
The two cookies
| Cookie | Purpose | Lifetime | Path |
|---|---|---|---|
pid_access | JWT access token, sent with every request | 15 minutes | / |
pid_refresh | Rotating refresh token, only used to mint new access tokens | 30 days | /v1/auth |
Both are HttpOnly; SameSite=Lax. In production the Secure flag is also set, so they
are only sent over HTTPS.
Sign-in flow
Browser PeridotID Google
│ POST /v1/auth/login │ │
│ ← {"url": "/v1/auth/google"} │
│ GET /v1/auth/google ──►│ 302 ─────────────────►│ consent screen
│ ◄────────────────────── │ │
│ ◄───────────────────────────── 302 + auth code ── │
│ GET /v1/auth/google/callback?code=... │
│ │ exchange code, create or link identity
│ ◄─ 302 CLIENT_SUCCESS_URL + pid_access + pid_refresh cookies- Call
POST /v1/auth/login(or use the SDK) to get the Google authorization URL. - Navigate the browser to that URL. The user consents on Google.
- Google redirects to
GET /v1/auth/google/callback?code=.... The API exchanges the code and resolves the credential. - Returning credential → session cookies are issued and the browser lands on
CLIENT_SUCCESS_URLwith a logged-in session. New credential → the PID picker (see below).
On a first-time sign-in the API mints a single-use claim ticket
(pid_claim cookie, 10 min) and redirects to CLIENT_SUCCESS_URL?claim=1. The claim
screen shows who you're continuing as — pick a handle, POST /v1/auth/claim, and the
identity (<handle>@pid), profile, and credential are created in one transaction.
Nothing exists until you claim: abandoning restarts cleanly on the next login, and an
expired ticket answers 410. On every later
sign-in the same Google credential is found and you land back on the same identity —
the PID never changes, is never reused, and cannot be reassigned, no matter which
providers you link or unlink later. Choose the handle carefully: it is permanent.
Note:
GET /v1/auth/googleand/v1/auth/google/callbackare browser-navigation only. They respond with302redirects that afetch()/Swagger "Send" call cannot follow (the cross-origin redirect to Google is CORS-blocked, showingFailed to fetch). Always open the login URL in a browser tab — never call these two endpoints from JavaScript.
Login credentials
Every way to log in — Google, Discord, Apple, email+password, passkeys — is a credential. Credentials belong to an identity:
- The pair
(provider, providerUserId)is unique — it is the source of truth. - A non-null
emailis unique across accounts: one email = one PID. If a new login presents an email already associated with another account, it is rejected with409(Email sudah terhubung dengan akun lain) — accounts are never merged, moved, or minted twice (see Errors). - The identity (PID) is the only source of truth. Credentials are just the keys that prove ownership of a PID.
List and unlink credentials via the SDK:
const credentials = await peridot.identity.credentials();
// [{ id, provider: "google", email, linkedAt, lastLoginAt }]
await peridot.identity.unlinkCredential(credentials[0].id);An identity must always keep at least one credential — unlinking the last one returns
400. This prevents a user from locking themselves out. Unlinking a credential never
touches the identity or its wallet (if any) — the wallet belongs to the PID, not to a
provider.
Refreshing tokens
The access token expires after 15 minutes. Instead of asking the user to log in again,
call POST /v1/auth/refresh. It:
- Verifies the current
pid_refreshcookie. - Revokes it (rotation) and issues a new access + refresh pair as cookies.
Because each refresh token can be used exactly once, a stolen token that is replayed after rotation is rejected.
curl -b cookies.txt -c cookies.txt -X POST https://api.pid.peridotvault.com/v1/auth/refresh
# 204 No Content — new cookies set, old refresh token revokedIf this returns 401, the refresh token is invalid, expired, or already rotated — the
user must sign in again.
Logging out
POST /v1/auth/logout revokes the current refresh token and clears both cookies. It is
idempotent — safe to call when already logged out.
curl -b cookies.txt -c cookies.txt -X POST https://api.pid.peridotvault.com/v1/auth/logoutSecurity notes
- Access tokens are short-lived; the real secret is the rotating refresh token.
- The refresh cookie's
Path=/v1/authmeans it is only sent to auth endpoints, reducing the window for cross-route exfiltration. - Auth endpoints are rate limited (see Errors).