Sessions and sign-out
A session is one signed-in browser or app. A web page carries it as a cookie; a native app carries it as a token. Both are the same server-side record, and ending it ends both.
What a sign-in sets
Section titled “What a sign-in sets”Every response that signs a user in answers 200 with the user and the session:
{ "user": { "id": "01926f3a-8b4c-7d2e-9f10-2a3b4c5d6e7f", "email": "ada@example.com", "emailVerified": true, "name": "Ada Lovelace", "firstName": "Ada", "lastName": "Lovelace", "image": null }, "session": { "id": "01926f3a-8b4d-7a11-8c22-3d4e5f6a7b8c", "kind": "edgekit", "expiresAt": "2026-08-30T09:00:00.000Z" }}The body never carries a token. The response sets:
- The session cookie, on the host the request reached, or on your organization’s cookie domain when EdgeKit has
set one. It is
HttpOnly, so page scripts cannot read it,SameSite=Lax, andSecureover HTTPS. - An access cookie for this site, which decide reads to know who the user is and what they hold.
Every EdgeKit cookie name starts with ek.. Over HTTPS, the session cookies’ names also carry __Secure- in front.
Read the session
Section titled “Read the session”GET /v1/id/get-session answers who is signed in. With no session it answers 200 with
{ "user": null, "session": null }, never 401. It is never cached.
const response = await fetch('/edgekit/v1/id/get-session', { credentials: 'include', headers: { 'x-edgekit-site-id': 'site_example' },});
const { user, session } = await response.json();
if (user === null) { // signed out}session.kind is edgekit for a session EdgeKit holds. At an external_only site it is external and id is
null, because the user was read from your login’s credential and EdgeKit holds no session; see
Choose who signs users in. Treat an unknown kind as signed in.
Reading the session also refreshes the site’s access cookie, so a grant the user just received reaches decide on the next page view.
In the browser client, id.session is the current state and id.subscribe calls you on every change. The state is
pending, anonymous, authenticated or unavailable; see
SessionState. The client reads the session the first
time you touch id.session, not on every window focus, and a sign-out in one tab reaches the others.
How long a session lasts
Section titled “How long a session lasts”A session lasts 30 days from when it was last extended. Reading it with GET /v1/id/get-session extends it to 30
days from that read, at most once a day. A user who comes back at least once a month stays signed in.
End a session
Section titled “End a session”POST /v1/id/sign-out ends the session the request carries. It deletes the server-side record, clears the session
cookie and every site’s access cookie the request carries, and answers 200 even when no session was sent, so a
retry is safe.
curl -X POST https://your-tenant-host/v1/id/sign-out \ -H 'x-edgekit-site-id: site_example' \ -H 'Authorization: Bearer <session-token>'{ "success": true, "logoutUrl": null }logoutUrl is null except at a dual site, where it is your own login’s sign-out page. Send the browser there too:
EdgeKit’s sign-out does not sign the user out of your login. See
Move users off your existing login.
Sign-out ends one session. The user’s other browsers and apps stay signed in. Every session a user holds ends when they change their email address; see Let users manage their account.
How quickly an ended session stops working
Section titled “How quickly an ended session stops working”Routes that change a user’s data check the session on every request, so an ended session is refused there at once:
/v1/id/user-details, /v1/id/change-identifier/* and /v1/org/*. Elsewhere it lingers in the browser that held
it:
GET /v1/id/get-sessioncan keep answering with the user for up to 15 minutes.- Decide reads the user from the site’s access cookie, and keeps doing so for up to an hour after that cookie was last refreshed.
Sign-out clears both cookies in the browser that signs out, so neither delay applies there.
Native apps
Section titled “Native apps”A native app has no cookie jar, so it carries the session as a token:
- Sign the user in as a page would, but send no
Originheader. A request with noOriginis refused when itsSec-Fetch-Siteheader is anything butsame-origin, so a native client sends neither header. - Read the session token from the
set-auth-tokenresponse header, and keep it in the platform’s secure storage. - Send it as
Authorization: Bearer <session-token>on later requests, together withx-edgekit-site-id.
curl -i -X POST https://your-tenant-host/v1/id/sign-in/email-otp \ -H 'x-edgekit-site-id: site_example' \ -H 'content-type: application/json' \ -d '{"email": "ada@example.com", "otp": "482913"}'# read the set-auth-token response header
curl https://your-tenant-host/v1/id/get-session \ -H 'x-edgekit-site-id: site_example' \ -H 'Authorization: Bearer <session-token>'Cross-origin JavaScript cannot read set-auth-token or send Authorization to EdgeKit. A page calling /edgekit/
on its own domain is same-origin, so it can read the header when your forwarder passes it through. Web pages use the
cookie, and the browser client never reads the token.
A user session is the only credential on these routes
Section titled “A user session is the only credential on these routes”The routes that act on the signed-in user accept a user session and nothing else. A request that carries an API key
in x-api-key is refused with 401 unauthorized, This route requires a user session., and a request with no
session gets 401 unauthorized, No user session.. An API key is for your servers’ routes, such as
/v1/id/upstream/*.
Sessions across your sites
Section titled “Sessions across your sites”A session works on every site its cookie reaches. By default the cookie belongs to the one host the user signed in
on. When EdgeKit sets your organization’s cookie domain, such as example.com, the cookie reaches every host under
it, so one sign-in covers www.example.com and shop.example.com. A deploy is refused when the cookie domain does not
cover every active site.
A site the cookie does not reach, such as one on example.net, gets its own sign-in, and the same address signs in to
the same user. See Call the tenant host directly.