Privacy
in plain text.
Last updated 2026-05-28. Chirp is operated by Stackwell Labs LLC. Questions: privacy@chirpauth.com.
What we collect
There are three places data can live: on our servers, on your device, or nowhere. Here's what is in each.
Stored on our servers
Here is everything we would return if you asked for a copy of your data, after signing up as janesmith@example.com, registering a passkey, signing into one app, and using the service for a few minutes. In our database the same information is split across several rows; we have combined it here for clarity.
{
"user": {
"user_id": "usr_a3f7c891b4e84d2c9f6012345678901a",
"email": "janesmith@example.com",
"created_at": "2026-05-28T21:14:00Z"
},
"passkeys": [
{
"passkey_id": "pk_a3f7c891b4e84d2c9f6012345678901a",
"derived_name": "Passkey on macOS",
"custom_label": null,
"public_key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgK...",
"created_at": "2026-05-28T21:15:00Z",
"last_used_at": "2026-05-28T22:30:00Z"
}
],
"sessions": [
{
"token": "bs_a3f7c891...90ab",
"created_at": "2026-05-28T21:14:00Z",
"last_seen_at": "2026-05-28T22:30:00Z",
"expires_at": "2026-06-27T21:14:00Z"
}
],
"consents": [
{
"app_id": "pigeon",
"scopes": ["openid"],
"approved_at": "2026-05-28T21:16:00Z"
}
],
"events": [
{
"event": "login.success",
"at": "2026-05-28T21:14:00Z",
"result": "success",
"detail": "id_token",
"trace_id": "trc_d2f3e4..."
},
{
"event": "login.email_step.started",
"at": "2026-05-28T21:13:50Z",
"detail": ""
}
]
}
Each field broken out:
| Field | Example | What it is | How long |
|---|---|---|---|
| user.user_id | usr_a3f7c891… | Opaque random account id. Internal stable handle that survives email changes; not derived from your email. | Until you delete your account. |
| user.email | janesmith@example.com | The identifier you sign in with. Where we send magic-link emails. | Until you delete your account. |
| user.created_at | 2026-05-28T21:14:00Z | When you first signed up. | Until you delete your account. |
| passkeys[] | { derived_name, custom_label, public_key, dates } | A passkey you registered. derived_name is auto-set at registration time to one of a small fixed list ("Passkey on macOS", "Passkey on iOS", etc.), computed from the OS family in your User-Agent. The raw User-Agent is read once for this and then discarded. custom_label is null by default; only populated if you explicitly rename the passkey on the account page. The public key is what we verify your sign-in signatures against; the private key never leaves your device. |
Until you remove the passkey. |
| sessions[] | { token, dates } | A browser session record — one per browser you have signed in from. Lets you stay signed in and lets you list and revoke sessions. No IP or browser fingerprint is attached. | 30 days absolute, 14-day idle — whichever first. |
| consents[] | { app_id, scopes, approved_at } | A relying app you have approved and the scopes you granted. Saved so we do not re-prompt on every sign-in. | Until you revoke consent. |
| events[] (security) | { event, at, result, detail, trace_id } | Sign-ins, account changes, passkey additions, etc. For incident response and your security audit on the account page. detail is a short fixed token like "id_token" or "ses", never a free-form string. No IP or browser fingerprint. |
30 days. |
| events[] (trace) | { event, at, detail } | Per-request diagnostic trace, for debugging when something goes wrong. The trace id (shown on error pages) is the storage key, not a stored field. No IP or browser fingerprint. | 14 days. |
| pending_magic_link (transient) | not present in this snapshot | A row that exists only between your clicking "send me a sign-in link" and your clicking the link in the email. Lets us verify the click came from the right inbox. | Usable more than once within the window, then deleted after 10 minutes — not consumed when you click it. |
| rate_limit_counter (transient) | RL#login.email#sha256(your_ip)#1748468040 | A per-IP counter that lets us reject brute-force sign-in floods. Your IP is SHA-256 hashed before becoming part of the key; we never store the raw IP. | Auto-deleted after 2 minutes. |
Stored only on your device
These live on your laptop, phone, or hardware key, and never reach our servers.
- Your passkey private keys — generated by your device, kept in the operating system's keychain or on a hardware security key (Touch ID, Windows Hello, a FIDO2 USB key). Chirp never sees them. We could not sign in as you even if our database were copied tomorrow: the cryptographic proof requires the private key, which we don't have.
- The session cookie — we generate a random token when you sign in and send it to your browser, which stores it for up to 30 days. It contains no information about you (see "Cookies" below for the full walkthrough). We don't track which physical device holds the cookie; we only know that requests arrive carrying tokens that map to sessions in our database.
- Cached pages and fonts — your browser caches our HTML, CSS, and font files the same way it caches any website. Not personal data; just bytes your browser saves to avoid re-downloading.
Not stored anywhere
- A password. Chirp has no passwords. Nothing to forget, leak, or crack.
- Your full IP address. Your IP is used for per-IP rate limiting during sign-in attempts, then discarded. The only persistent trace is the 2-minute SHA-256 hash described above, which auto-deletes. We never write your raw IP to any durable storage.
- Your browser's User-Agent header. Your browser sends it on every request, but our code only reads it in one specific place: when you register a passkey, to derive a name like "Passkey on macOS" from a fixed list of OS families. The raw User-Agent string itself is never stored anywhere.
- The contents of your email inbox beyond the magic-link emails we sent you.
- Your activity inside the apps you sign into. Once we issue an authorization code and the relying app takes over, we don't see what you read, click, or write on that app. What it does with you is governed by its own privacy policy.
Why we collect it
Only to operate the sign-in service: authenticate you, issue tokens to the application you chose, let you manage your sessions and passkeys, prevent abuse, and respond to security incidents. We do not sell, share, or use this data for advertising or profiling.
Who we share it with
When you complete a sign-in to a relying application, we issue that application an ID token containing only a pairwise subject identifier (unique to that application) and the standard OIDC claims. We never share your email address with the application — there is no email scope and the token carries no email claim. The relying application then becomes a separate data controller for what it does with the identifier — check its own privacy policy.
We use a small number of infrastructure providers as data processors: Amazon Web Services (compute, storage, and outbound email via SES) and Route 53 (DNS). They process data on our instructions; they do not receive your data for their own use.
How long we keep it
Account records (email, registered passkeys) are kept while your account exists. Sessions last up to 30 days from creation, with a 14-day idle timeout, and are deleted automatically after either limit. Security event logs (sign-in successes, failures, account changes) are kept for 30 days. Per-request diagnostic logs are kept for 14 days. In-flight magic links expire and are deleted within 10 minutes.
Your choices
- See your sessions: visit your account page.
- Sign out everywhere: revoke all sessions from the same page.
- Delete your account: do it yourself from your account page — choose “Delete your account”, confirm once, and we erase your record and all associated sessions, passkeys, and consents on the spot. No email-us-to-erase ritual. If your account is blocked from self-deletion (for example because it still owns registered apps), email privacy@chirpauth.com and we’ll handle it.
- Access a copy of your data: email privacy@chirpauth.com.
If you are in the EU/UK or California, the GDPR / CCPA give you specific rights (access, deletion, correction, portability). Deletion is self-serve from your account page; for data export or any request you can’t complete yourself, email privacy@chirpauth.com.
Cookies
We set one essential cookie: a random session token, used solely as a lookup key for your server-side session. It contains no personal information — not your email, not your name, not your account id, not even when it expires. We do not use analytics, advertising, or third-party cookies.
Here is exactly what the cookie looks like if you sign in as janesmith@example.com:
chirp_auth_session=bs_a3f7c891b4e84d2c9f6012345678901a_d4e5f6789012345678901234567890ab; Path=/; Max-Age=2592000; HttpOnly; SameSite=Lax; Secure
Each piece broken out:
| Key | Value | What it is | Why it's here |
|---|---|---|---|
| chirp_auth_session | bs_a3f7c891…90ab | The cookie's name and opaque value. | The value is a 244-bit random server-side lookup key. Nothing about you (no email, no account id) is encoded in it. |
| Path | / | URL-path scope within the origin. | Sent on every request to signin.chirpauth.com — never to other origins, never to the relying apps you sign in to. |
| Max-Age | 2592000 | Lifetime in seconds (30 days). | Browser auto-deletes after. The server independently expires sessions after 14 days of inactivity, so an old cookie can stop working before this clock runs out. |
| HttpOnly | — | Hidden from JavaScript. | Blocks the most common cookie-theft vector: a cross-site-scripting bug on any page reading the cookie via document.cookie. |
| SameSite | Lax | Cross-origin send rule. | Sent on top-level navigations (so OIDC sign-in redirects work) but not on third-party POSTs (CSRF protection). |
| Secure | — | HTTPS-only. | Cookie is never transmitted over plain HTTP. |
When Jane signs out, we delete her session row from the server and instruct her browser to clear the cookie. The token stops working immediately, even if a copy of it had been intercepted somewhere — because the lookup target is gone.
Security
All traffic is HTTPS. Magic links are short-lived. Passkey private keys never leave your device. We rotate signing keys and publish JWKS at /.well-known/openid-configuration. To report a security issue, email abuse@chirpauth.com.
Changes
If we change this policy in a way that materially expands what we collect or share, we’ll update the date above and notify active accounts by email at least 14 days before the change takes effect.