Get a session
in two steps.
Streamwake doesn't use API keys. Better-auth sets an httpOnly cookie on signup and sign-in, and every /api/v1/* route reads it on the way in. The same cookie drives /app/streams, /app/agents, and /app/integrations — sign in once, every surface knows you.
requireAuth() reads it on every gated route — no client-side checks to bypass.Create an account
The fastest path is the UI at /sign-up. The form collects name, email, and password, calls authClient.signUp.email, and on success sets the session cookie before navigating you to /app/streams.
Need to script it? The same flow is exposed as a REST endpoint. The request body is what better-auth accepts, and the response sets the cookie you'll send back on every call below.
curl -X POST https://streamwake.polsia.io/api/auth/sign-up/email \
-H "content-type: application/json" \
-d '{
"name": "Your Name",
"email": "you@example.com",
"password": "choose-a-strong-password"
}'HTTP/2 200
Set-Cookie: better-auth.session_token=<your-session-token>; HttpOnly; SameSite=Lax; Path=/
Content-Type: application/json
{
"token": "<your-session-token>",
"user": {
"id": "ckq3xuserabc123",
"email": "you@example.com",
"name": "Your Name"
}
}The session cookie
On a successful signup or sign-in, better-auth's catch-all handler at /api/auth/[...all] responds with a Set-Cookie header:
- Name:
better-auth.session_token - Flags:
HttpOnly,SameSite=Lax,Path=/ - Read by: the server in
requireAuth(req)(callsauth.api.getSession) at the top of every gated route.
The cookie is opaque to JavaScript — pull it from your browser's devtools (Application → Cookies) when you want to script curls against the API.
curl -X POST https://streamwake.polsia.io/api/auth/sign-in/email \
-H "content-type: application/json" \
-c cookies.txt \
-d '{
"email": "you@example.com",
"password": "your-password"
}'The -c flag writes the response cookies to cookies.txt; pair it with -b on subsequent calls to send them back.
Use it on every API call
Every /api/v1/* route requires the cookie. Pass it on the request line as -b "better-auth.session_token=<value>".
The same cookie also drives every authenticated dashboard page — /app/streams, /app/agents, and /app/integrations all read it via useSession() from @/lib/auth-client.
curl https://streamwake.polsia.io/api/v1/streams/ckq3xstreamabc123 \
-b "better-auth.session_token=<your-session-cookie>"Failure modes
Three response codes you can hit during development. The first means re-auth; the second means a request-body issue; the third is a retry.
Unauthorized
Cookie is missing, expired, or tampered. Re-auth via /api/auth/sign-in/email and retry. Body is the verbatim { "error": "Unauthorized" } returned by require-auth.ts.
Validation / SSRF
POST bodies fail zod validation or the sourceUrl fails the SSRF guard. Body is { "errors": { "field": "..." } }.
Internal Server Error
Unexpected server failure. Body is { "error": "Internal Server Error" }. Safe to retry.
URL could not be parsedOnly http(s) URLs are allowedURL has no hostnameHostname did not resolveHostname resolves to a private address (<ip>)
The landing CTA is a waitlist.
The developer path is a cookie.
The form on the home page — <GetApiKeyForm/> — captures an email and writes it to the waitlist. It does not issue a credential today. If product ships real API keys later, that's a separate Prisma model plus bearer-token auth wired into require-auth. The path that works right now is signup → cookie session.