Skip to content
RELKIT
Esc
↑↓navigate↵open⌘Jpreview
On this page

Read sessions

Read the request's verified identity in a business function, handle anonymous callers, and understand session types and non-HTTP limits.

Read the current caller’s session inside a function with await context.auth.getSession(). It returns the Better Auth session result or null. The result contains both the session record and the user; the verified user ID is session.user.id, not a user-supplied request field.

Read an optional session

The example’s account operation supports anonymous and authenticated requests:

/** Reads the invocation's native session and returns validated authentication and user identity fields. */
import { defineFunction } from "@relkit/app/functions";
import { z } from "@relkit/app/schema";

export default defineFunction({
  input: z.object({}),
  output: z.object({ authenticated: z.boolean(), userId: z.string().optional() }),
  handler: async (_input, context) => {
    const session = await context.auth.getSession();
    return session === null
      ? { authenticated: false }
      : { authenticated: true, userId: session.user.id };
  },
});

Its output deliberately returns only an authentication flag and user ID. Do not return the complete session object simply because it is available: auth records can contain tokens, IP addresses, and other private data. Define the response your caller needs.

The compiler generates auth context types from the registered service’s handler. Functions do not add a dependencies.auth entry, import a global auth instance, or open a database connection. Run bun run check after changing registration or type-affecting auth options, then bun run typecheck. Inspect .relkit/generated/context-registry.d.ts if the expected auth type is missing; do not edit it.

Choose public or authenticated access

The operation is registered by an ordinary domain service:

/** Exposes native session observation as the account boundary used by profile and session routes. */
import { defineService } from "@relkit/app/services";
import session from "./functions/session.function.js";

export default defineService({ functions: { session } });

Its public route is:

/** Maps session GET requests to account session observation, including the explicit anonymous result. */
import { defineRoute } from "@relkit/app/routes";
import account from "@app/services/account/service.js";

export const GET = defineRoute({ target: account.session });

GET /session returns HTTP 200 with { "authenticated": false } when signed out. The same function is also mounted at /account/profile, which the auth mount protects; there, an anonymous request receives 401 before the function runs. See Protect routes.

Even behind a protected route, keep function behavior safe for a missing session. That function may later have another caller or transport. For operations that require identity, reject a missing session using an application declared error, then verify permission before reading or modifying protected records. A non-null session is not a role or ownership check.

Understand request-scoped lookup

Session resolution uses the incoming request headers. It is lazy: a public operation that never calls getSession() does not need that lookup. The HTTP runtime memoizes the lookup promise for the request, including the lookup used by route protection. Concurrent reads within that request share the result; this is not an application-wide identity cache.

Do not save the session in module state or reuse it for another request. A lookup already completed in a request is not a fresh authorization check after revocation or account changes within that same request. Use separate requests to verify lifecycle changes such as sign-out.

context.auth.getSession() returns data, not a native HTTP Response. Do not assume it forwards Better Auth’s Set-Cookie headers to the browser. Use the native auth endpoints and client for sign-in, sign-out, and session lifecycle flows.

Work without an HTTP request

Jobs and direct invocations do not acquire a browser session merely because an auth service exists. Without an active HTTP auth context, session lookup resolves to null. The Inspector is not a way to impersonate a signed-in browser by supplying a userId input.

For deferred work, authorize the enqueue operation, record the relevant actor/resource identifiers in the job’s validated input, and define which permissions must be rechecked at execution time. Do not put cookies, passwords, or session tokens in queued payloads. A client-supplied actor ID is untrusted until the authenticated entry point validates it.

For unit tests, inject an explicit auth context; for request behavior, use the real HTTP harness in Auth testing. Neither approach requires reading a developer’s browser cookies.

Reference and source