clerk
On this page:
- spider.clerk: Authentication through Clerk.
spider.clerk
Clerk login (spider.clerk): the token check of spider.jwks configured from a Clerk publishable key, plus the OAuth login redirect and the callback that sets the session cookie.
spider.clerk.ClerkConfig
pub const ClerkConfig = struct
What Clerk.init takes. Nothing is read from the environment: the app fills it.
Fields
publishable_key: []const u8: The instance's publishable key (pk_test_...orpk_live_...). The issuer and the JWKS URL are derived from it (seeClerk.init); it is also sent as the OAuthclient_id. No default.secret_key: []const u8: Sent as the OAuthclient_secretwhen the callback exchanges the code. No default.redirect_uri: []const u8 = "http://localhost:3000/auth/callback": The full URL of the app's callback route (callbackHandler()).login_path: []const u8 = "/login": Where a request without a token is redirected.after_callback_path: []const u8 = "/": Where the callback redirects once the session cookie is set.roles_claim: ?[]const u8 = null: Where the session token carries roles (what.roleschecks); Clerk has none by default — add one with a custom session claim, e.g. {"roles": "{{user.public_metadata.roles}}"} androles_claim= "roles". The active organization's role (what.org_roleschecks) is read without configuration. See JwksConfig.roles_claim.map_claims: ?*const fn (c: *Ctx, claims: std.json.ObjectMap) anyerror!void = null: See JwksConfig.map_claims.verify_state: bool = true: Check the OAuthstateon the callback against the cookieloginHandler()set, so that nobody can finish a login of their own in a visitor's browser. Every login must then start atloginHandler()(orlogin): the callback of a hand-built URL has no matching cookie and is sent back tologin_path.state_cookie_name: []const u8 = "__clerk_oauth_state": Cookie that keeps the state (HttpOnly, SameSite=Lax, 10 minutes; Secure unlessredirect_uriis plain http, like the session cookie).
spider.clerk.AuthUrlOptions
pub const AuthUrlOptions = struct
Options of Clerk.authUrlWith.
Fields
state: ?[]const u8 = null: Sent to Clerk and given back to the redirect address as?state=.
spider.clerk.Clerk
pub const Clerk = struct
One Clerk instance for the app. The middleware and the callback handler keep a pointer to this value: it must not move or be freed while the server runs, and a process can use one.
var clerk = try spider.clerk.Clerk.init(allocator, io, .{
.publishable_key = publishable_key,
.secret_key = secret_key,
});
defer clerk.deinit();
server
.use(clerk.middleware())
.get("/login", clerk.loginHandler(), .{ .public = true })
.get("/auth/callback", clerk.callbackHandler(), .{ .public = true });
Fields
jwks: JwksAuth: The token verifier (spider.jwks.JwksAuth), with.org_claims = .clerk.config: ClerkConfig: The config given toinit. Its strings are not copied.domain: []const u8: The issuer decoded from the publishable key: the base of the JWKS and OAuth URLs.
clerk.Clerk.init
pub fn init(allocator: std.mem.Allocator, io: std.Io, config: ClerkConfig) !Clerk
Decodes the issuer from the publishable key and downloads the signing keys from {issuer}/.well-known/jwks.json. What follows the key's pk_live_ / pk_test_ prefix is base64 of the host of the instance's Frontend API followed by a $ (example.accounts.dev$): the issuer is that host over https. (A key that decodes to JSON with an issuer field is used as that issuer, scheme included: for tests against a server of your own.)
Errors: error.InvalidClerkKey (no such prefix, not base64, or it decodes to nothing), error.JwksFetchFailed when the address does not answer with a key set, or the HTTP client's error when it cannot be reached.
clerk.Clerk.deinit
pub fn deinit(self: *Clerk) void
Frees the cached keys and the two addresses init built.
clerk.Clerk.authUrl
pub fn authUrl(self: *const Clerk, arena: std.mem.Allocator) ![]u8
The URL that starts the OAuth flow ({issuer}/oauth/authorize), without a state. Allocated in arena; the values are URL-encoded. A login route calls login (or mounts loginHandler()), which adds the state the callback checks.
clerk.Clerk.authUrlWith
pub fn authUrlWith(self: *const Clerk, arena: std.mem.Allocator, opts: AuthUrlOptions) ![]u8
authUrl with a state, URL-encoded like the rest.
clerk.Clerk.loginHandler
pub fn loginHandler(self: *Clerk) Handler
The handler for the login route (login_path): login.
clerk.Clerk.login
pub fn login(self: *Clerk, c: *Ctx) !Response
Redirects (302) the visitor to Clerk with a random state, also kept in a cookie of this browser; callbackHandler() compares the two.
clerk.Clerk.middleware
pub fn middleware(self: *Clerk) MiddlewareFn
The middleware that checks the __session token of every request (see JwksAuth.middleware): server.use(clerk.middleware()). Only routes marked .public pass without a token (there is no list of skipped paths), an expired token is a 401 (there is no refresh route), and the token's audience is not checked.
clerk.Clerk.callbackHandler
pub fn callbackHandler(self: *Clerk) Handler
The handler for the route named by redirect_uri: checks the state against the cookie login set (when it does not match: redirect to login_path, and Clerk is not asked anything), exchanges code for tokens, sets the __session cookie (the ID token, or the access token when there is none; 7 days), removes the state cookie and redirects to after_callback_path. 400 without code; 502 when Clerk returns no token. Mark the route .public, or the middleware stops the callback before it gets here.