Authentication
DSN credentials for ingest; session cookies for /api/v1. They are not interchangeable.
Epure uses two auth mechanisms.
What is DSN vs session?
The DSN authenticates ingest. Dashboard /api/v1/* uses a session cookie and RLS app.current_org_id.
| Surface | Paths | Credential | Scope |
|---|---|---|---|
| Ingest | /api/{project_id}/envelope/, /store/, /releases/…/files/, /user-feedback/ | DSN public + secret key | Project (and parent org) from the key |
| Dashboard | /api/v1/* (except public auth routes) | Session cookie | Org from session; RLS app.current_org_id |
Sending a session cookie to ingest does nothing. Sending DSN headers to /api/v1/issues returns 401 { "error": "unauthenticated" }.
How does DSN ingest auth work?
Credentials come from a project DSN key. Create or rotate one in the UI, or via /api/v1/projects/{id}/dsn-keys.
Preferred outside browser SDKs:
X-Sentry-Auth: Sentry sentry_version=7, sentry_key={public_key}, sentry_secret={secret_key}Secret comparison is constant-time.
DSN URL shape
http://{public_key}:{secret_key}@{host}/{project_id}or public-key-only forms depending on the SDK. The path {project_id} must match the key’s project.
| Status | error | What to do |
|---|---|---|
403 | project_mismatch | Use the project UUID from the DSN |
403 | dsn_revoked | Create or rotate a key |
401 | invalid_dsn | Check sentry_key / header spelling |
CORS
Ingest routes answer OPTIONS for browser SDKs. Allowed request headers include X-Sentry-Auth, Content-Type, Content-Encoding. Origins: Configuration.
How does session auth work?
After password or Google login, the server sets an HttpOnly cookie backed by Postgres tower-sessions.
| Mode | Cookie name |
|---|---|
Secure (EPURE_SESSION_SECURE=1, default prod) | __Host-epure.sid |
Local HTTP (EPURE_SESSION_SECURE=0) | Epure.sid |
Attributes: HttpOnly, SameSite=Lax, Path=/, inactivity expiry 14 days.
No bearer tokens in localStorage.
Login
curl -sS -c cookies.txt -D - -o /dev/null -X POST \
"http://localhost:8080/api/v1/auth/login" \
-H "Content-Type: application/json" \
-d '{"email":"dev@epure.local","password":"devpassword"}'| Result | Meaning | What to do |
|---|---|---|
204 + Set-Cookie | Session established | Reuse -b cookies.txt on /api/v1/* |
| 401 | Bad email/password | Check seed user or register |
| 429 plain text | 20 req / IP / 60s | Wait |
Public /api/v1/auth routes
| Method | Path | Notes |
|---|---|---|
GET | /api/v1/auth/config | { google_enabled, password_enabled } |
POST | /api/v1/auth/register | email + password (+ optional invite_token) |
POST | /api/v1/auth/login | email + password → 204 |
GET | /api/v1/auth/google | OIDC start |
GET | /api/v1/auth/google/callback | OIDC callback |
GET | /api/v1/auth/me | current session (requires cookie) |
POST | /api/v1/auth/logout | clear session |
POST | /api/v1/auth/accept-invitation | { invite_token } |
PATCH | /api/v1/auth/profile | { display_name } |
PATCH | /api/v1/auth/password | change password |
DELETE | /api/v1/auth/account | delete account |
Login body:
{ "email": "you@example.com", "password": "your-password", "invite_token": null }Login succeeds but later /api/v1 calls are 401?
The browser rejected the cookie over an HTTPS vs EPURE_SESSION_SECURE mismatch. Local HTTP needs 0 (Epure.sid); HTTPS needs 1 (__Host-epure.sid). DSN headers on this path also return 401, so use the cookie. See Troubleshooting.
Can I use the DSN as a bearer token?
No, and there are no bearer tokens in localStorage either. The DSN covers ingest only: envelope, store, release files, user feedback. Issues and Events need the login cookie. The tables above list which header belongs on which path.