SERVER / SESSIONS

Opaque sessions

Bearer describes how a credential travels. It does not require JWT. Dowe's CRUD template uses a server-owned ULID session backed by Cache and Database.

1 / MENTAL MODEL

Use an opaque ULID as the session id

id session source:"ulid" generates a canonical 26-character ULID on the server. The client receives only the opaque id and sends it as Authorization: Bearer <ulid>. Claims and database credentials never enter the token.

dowe
fn createSessionRepository params:{ userId:string }
  id session source:"ulid"
  query created conn:appDb.insert table:"sessions" value:{ id:session userId:args.userId createdAt:now } required:["id" "userId"]
  str sessionKey source:"join" values:["session" session] delimiter:":"
  kv cached conn:appCache.set key:sessionKey value:{ id:session userId:args.userId }
  return value:{ id:session userId:args.userId }
Layer
Responsibility

No data

There are no records to display

2 / MIDDLEWARE

Validate Cache first, then Database

session.verify rejects malformed or expired ULIDs, checks Cache, falls back to the sessions table, and returns valid:false when the session is absent. Only verified data should reach next context.

dowe
import { appDb, appCache } from "@/server/config/database"

middleware requireBearer
  bearer token value:req.header.Authorization
  session verified cache:appCache database:appDb token:token maxAge:2592000
  if verified.valid
    next context:{ auth:{ subject:verified.userId session:verified.id authorization:req.header.Authorization token:token } }
  return status:401 json:{ ok:false error:"Unauthorized" }
Step
Result

No data

There are no records to display

3 / LIFECYCLE

Expiration and logout are stateful

The default CRUD maxAge is 30 days. Runtime checks the ULID timestamp on every validation. Logout deletes both session:<ulid> from Cache and the matching sessions record, so revocation is immediate.

dowe
fn logoutUserService params:{ session:string }
  deleteSessionRepository deleted args:{ id:args.session }
  return value:{ authenticated:false guest:true authorization:"" token:"" }
Concern
Rule

No data

There are no records to display

4 / DESIGN CHOICE

When should you use JWT?

Choose the credential model from the authority your application needs: shared state favors immediate revocation, while signed assertions favor independent verification.

Model
Choose it when

No data

There are no records to display