Authentication
People sign in with Google and get a session cookie, and until personal API tokens exist, a script sends that same cookie.
Signing in#
Google is the only way to sign in. A browser starts at GET /api/v1/auth/google, which sends the person to Google. Google returns them to Rigel, Rigel creates a session and sets its cookie, and the browser lands back in the app. The flow needs a browser, so a script doesn't run it. See using it from a script.
Rigel is in early access, and only people it has let in can create an account. A Google account Rigel doesn't know is sent back to the app with sign_in_error=signup_closed in the URL, and no account is made. The other values are cancelled (the person backed out at Google), google_failed (the attempt expired; start again) and email_unverified.
Signing out is POST /api/v1/auth/sign-out. It ends the session and clears the cookie, and it succeeds even when nobody is signed in.
The session cookie#
A signed-in browser holds a cookie named rigel_session. Its value looks like ses_01JC4M7V2S9A3B5D7F1G2H4J6K. followed by 64 hexadecimal characters. The cookie is HttpOnly, Secure and SameSite=Lax, so a page's scripts can't read it, and most cross-site requests don't carry it.
- A session lasts 30 days from the moment of sign-in. After that, requests get 401 until you sign in again.
- Signing out deletes the session on the server. A copy of the cookie stops working at once.
- One person can have many sessions, one for each browser or device they signed in on. Ending one doesn't end the others.
Using it from a script#
Personal API tokens aren't built yet. Until they are, a script borrows a browser's session.
- Sign in at
https://rigel.house. - In the browser's developer tools, open the cookies for rigel.house and copy the value of
rigel_session. It doesn't show indocument.cookie, because it isHttpOnly. - Send it as a
Cookieheader on every request.
curl -sS https://rigel.house/api/v1/me \
-H "Cookie: rigel_session=$RIGEL_SESSION"const response = await fetch("https://rigel.house/api/v1/me", {
headers: { Cookie: `rigel_session=${process.env.RIGEL_SESSION}` },
});
console.log(response.status, await response.json());Call the API from a script or a server. It sends no CORS headers, so a page on another site can't call it, and a browser doesn't let a page set the Cookie header anyway.
What is public and what isn't#
These routes need no session:
| Route | What it is |
|---|---|
GET /api/v1/health | Returns { "ok": true }, for monitors. |
GET /api/v1/openapi.json | The OpenAPI 3.1 document for every operation. |
GET /api/v1/docs | An interactive view of that document. |
GET /api/v1/socket-schema.json | JSON Schema for the messages on the household socket. |
/api/v1/auth/… | The sign-in flow and sign-out. |
GET /api/v1/integrations/google/callback | Where Google sends a browser back after a member connects an outside account. It checks the session itself and always redirects. See outside accounts. |
Every other route that reads or changes data needs a session, including GET /api/v1/me and every household route, files included. A request without a valid session is refused before anything else is checked.
401 and 404#
401 unauthenticated means the cookie is missing, malformed, expired, or from a session that was signed out. Sign in again and send a new cookie.
{
"error": {
"code": "unauthenticated",
"message": "You're not signed in.",
"details": {},
"recovery": "Sign in, then send the request again.",
"request_id": "req_01JC4N9D6R2T5W8Y1A4C7E0G3J"
}
}404 not_found on a household route means you are signed in, and the household either doesn't exist or you aren't a member of it. The two cases return the same response on purpose. Knowing a household's ID gives you nothing, and the API doesn't confirm which IDs are real. If you get a 404 for a household you expect to reach, check that the ID is right and that the cookie belongs to the account that is a member.
{
"error": {
"code": "not_found",
"message": "That household wasn't found.",
"details": {},
"recovery": "Check the ID. You can only reach households you're a member of.",
"request_id": "req_01JC4N9D8T4V7Y0A3C6E9G2K5M"
}
}What is planned#
These are designed but not built.
- Personal API tokens. A person creates a token for their own scripts. Each token is for one household and is either read-only or read-write. It is shown once, stored hashed and can be revoked. Tokens can't manage tokens, members or roles, or erase anything. What a token does is recorded as the token's, not as the person's. A token is sent as
Authorization: Bearer <token>. - Android sessions. The Android app will sign in with Google on the device and exchange the result for its own session token, sent as a bearer token. It follows the same lifetime and revocation rules as a web session.
When tokens exist, the examples on this site will switch from the Cookie header to the Authorization header. Paths, bodies and responses won't change.