Session
How Clowk manages sessions in Rails
Overview
When a user authenticates through Clowk, your Rails app receives a JWT. The clowk gem handles session management automatically — it verifies the token, stores the user data in the Rails session, and sets an HTTP-only cookie.
The callback flow
After the user authenticates on Clowk's hosted page, they are redirected back to your app:
GET /clowk/oauth/callback?token=eyJ...&state=abc123The clowk gem's callback controller:
- Validates the state — compares the
stateparameter against the value stored in the session before the redirect (CSRF protection) - Verifies the JWT — decodes the token with your secret key (HS256), checks the issuer and expiration
- Resets the session — clears any previous session data to prevent session fixation
- Persists the new session — stores the token and decoded payload in the Rails session and sets a cookie
What gets stored
Rails session
session[:clowk] = {
token: "eyJ...",
user: {
sub: "user-uuid",
email: "jane@example.com",
name: "Jane Doe",
avatar_url: "https://...",
provider: "google",
instance_id: "inst_abc123",
app_id: "app_xyz789"
},
signed_in_at: 1711152000
}The session key is configurable via config.session_key (default: :clowk).
HTTP-only cookie
Set-Cookie: clowk_token=eyJ...; HttpOnly; SameSite=Lax; SecureThe cookie stores the raw JWT token as a fallback. It's:
- HttpOnly — not accessible via JavaScript
- SameSite=Lax — protects against CSRF
- Secure — only sent over HTTPS (when the request is SSL)
The cookie name is configurable via config.cookie_key (default: "clowk_token").
Reading the session
When you call current_clowk, the gem reads the session in this order:
- Rails session first — checks
session[:clowk][:user]for the cached payload - Token extraction fallback — if the session is empty, extracts the token from:
- Query parameter (
?token=eyJ...) - Authorization header (
Bearer eyJ...) - Cookie (
clowk_token)
- Query parameter (
- Verifies and re-persists — if a token is found via extraction, verifies it and saves it back to the session
current_clowk # => Clowk::Current object or nil
current_clowk.email # => "jane@example.com"
current_clowk.name # => "Jane Doe"
current_clowk.id # => "user-uuid" (from the "sub" claim)The result is cached in @clowk_current_resource for the duration of the request.
Sign-out
When the user signs out (via /clowk/sign_out):
def clowk_sign_out!
session.delete(:clowk) # Remove session data
cookies.delete('clowk_token') # Remove the cookie
@clowk_current_resource = nil # Clear the request cache
endAfter sign-out, current_clowk returns nil and clowk_signed_in? returns false.
Token expiration
Clowk JWTs expire after 1 hour. When a token expires:
current_clowkreturnsnil(theJwtVerifierraisesInvalidTokenError, which is caught and returnsnil)authenticate_clowk!redirects to the sign-in page (or returns 401 for JSON requests)- The user needs to sign in again through the Clowk hosted page
The session data (stored in the Rails session) does not have its own TTL — it relies on the JWT expiration for validity.
Session flow diagram
Sign-in:
1. User clicks sign-in → redirect to Clowk
2. Clowk authenticates → redirect back with ?token=eyJ...
3. Callback controller verifies JWT
4. Stores { token, user, signed_in_at } in session[:clowk]
5. Sets clowk_token cookie (HttpOnly, Secure, SameSite=Lax)
6. Redirects to after_sign_in_path
Subsequent requests:
1. current_clowk reads session[:clowk][:user]
2. Returns Clowk::Current object with id, email, name, etc.
Sign-out:
1. User visits /clowk/sign_out
2. Deletes session[:clowk] and clowk_token cookie
3. Redirects to after_sign_out_pathJavaScript SDKs
The JavaScript SDKs (@clowk/react, @clowk/nextjs) manage sessions differently:
- React —
ClowkProviderwatches for?token=on mount, stores the JWT in a cookie (clowk_token), and decodes the user payload into React state - Next.js —
clowkMiddlewarereads the token from cookies or headers on each request.auth()verifies the token server-side and returns{ user, token, signedIn } - Express / Hono —
clowkMiddlewareextracts and verifies the token on each request. No server-side session is maintained — the JWT itself is the session
In all cases, the token is the single source of truth. When it expires, the user must re-authenticate.