Skip to content

feat(core): introduce server API via createAuth#112

Open
halvaradop wants to merge 2 commits intomasterfrom
feat/introduce-server-api
Open

feat(core): introduce server API via createAuth#112
halvaradop wants to merge 2 commits intomasterfrom
feat/introduce-server-api

Conversation

@halvaradop
Copy link
Member

@halvaradop halvaradop commented Mar 3, 2026

Description

Related Changes to Introduce

  • toWebHandler function

Summary by CodeRabbit

Release Notes

  • New Features

    • Introduced unified server API for centralized session management across all frameworks
    • Standardized authentication responses with authenticated flag and session object structure
  • Bug Fixes

    • Improved session validation using explicit authentication state checks
    • Consolidated session retrieval logic for consistent behavior across applications

@vercel
Copy link

vercel bot commented Mar 3, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
auth Ready Ready Preview, Comment Mar 3, 2026 8:52pm
auth-nextjs-demo Ready Ready Preview, Comment Mar 3, 2026 8:52pm

@coderabbitai
Copy link

coderabbitai bot commented Mar 3, 2026

📝 Walkthrough

Walkthrough

The PR introduces a centralized server API for session management across all framework implementations. New types (SessionResponse, AuthServerAPI) are added to the core package, along with a context factory (createContext) and server utility (createServerAPI). Local getSession helpers are removed from each framework and replaced with server.getSession() calls. The session response structure is standardized to include both authenticated flag and session object properties.

Changes

Cohort / File(s) Summary
Core types and context
packages/core/src/@types/index.ts, packages/core/src/context.ts
Added SessionResponse union type, AuthServerAPI interface with getSession method, and augmented AuthInstance and RouterGlobalContext with server property. Created createContext factory for centralized context initialization.
Core server API and session action
packages/core/src/server/create-server.ts, packages/core/src/actions/session/session.ts, packages/core/src/index.ts
Introduced createServerAPI utility that provides session retrieval with JWT validation and logging. Updated session endpoint to use server API instead of manual JWT decoding. Modified createAuth to include server in public exports.
Bun framework
apps/bun/src/auth.ts, apps/bun/src/index.ts, apps/bun/src/lib/get-session.ts
Added server to auth destructuring. Replaced getSession(request) with server.getSession(request) in protected route. Removed local getSession helper. Updated session validation to check session.authenticated.
Deno framework
apps/deno/src/auth.ts, apps/deno/src/index.ts, apps/deno/src/lib/get-session.ts
Added server to auth destructuring. Replaced direct getSession(request) call with server.getSession(request). Removed local helper module.
Elysia framework
apps/elysia/src/auth.ts, apps/elysia/src/lib/get-session.ts, apps/elysia/src/plugins/with-auth.ts
Added server to auth exports. Updated with-auth plugin to use server.getSession(ctx.request) and check session.authenticated flag. Removed local getSession helper.
Express framework
apps/express/src/auth.ts, apps/express/src/lib/get-session.ts, apps/express/src/lib/verify-session.ts
Added server to auth exports and dynamic oauth configuration. Updated verify-session middleware to use server.getSession(toWebRequest(req)). Removed local getSession helper with JWT decoding logic.
Hono framework
apps/hono/src/auth.ts, apps/hono/src/lib/get-session.ts, apps/hono/src/middleware/with-auth.ts
Added server to auth destructuring. Updated with-auth middleware to call server.getSession(ctx.req.raw) and validate session.authenticated. Removed local helper.
Oak framework
apps/oak/src/auth.ts, apps/oak/src/lib/get-session.ts, apps/oak/src/middleware/with-auth.ts
Added server to auth exports. Modified middleware to use server.getSession(ctx.request) and check session.authenticated. Removed local getSession helper.
Supabase framework
apps/supabase/functions/_shared/auth.ts, apps/supabase/functions/_shared/get-session.ts, apps/supabase/functions/auth/index.ts
Added server to auth exports. Replaced getSession(request) with server.getSession(request) in auth endpoint. Removed shared getSession helper. Updated response shape handling.
Tests and configuration
packages/core/test/actions/session/session.test.ts, packages/core/.vscode/settings.json
Updated session endpoint tests to reflect new response structure with authenticated and session fields. Added VSCode workspace settings file.

Sequence Diagram

sequenceDiagram
    participant Client
    participant AuthServer as Server (Request Handler)
    participant SessionAPI as Server.getSession()
    participant CookieStore as Cookie Store
    participant JoseValidator as JWT Validator

    rect rgb(200, 150, 255, 0.5)
    Note over Client,JoseValidator: Old Flow (Local getSession)
    Client->>AuthServer: GET /api/protected
    AuthServer->>AuthServer: Build request to /api/auth/session
    AuthServer->>AuthServer: Forward request headers
    AuthServer->>AuthServer: Manually parse JWT from headers
    AuthServer->>AuthServer: Decode JWT with jose
    AuthServer->>Client: Return session or null
    end

    rect rgb(150, 200, 150, 0.5)
    Note over Client,JoseValidator: New Flow (Centralized Server API)
    Client->>AuthServer: GET /api/protected
    AuthServer->>SessionAPI: server.getSession(request)
    SessionAPI->>CookieStore: getCookie(request, sessionToken)
    CookieStore->>SessionAPI: session_token_value
    SessionAPI->>JoseValidator: decode JWT
    JoseValidator->>SessionAPI: { user, exp, ...claims }
    SessionAPI->>SessionAPI: Validate authenticated status
    SessionAPI->>AuthServer: SessionResponse { authenticated, session }
    AuthServer->>Client: Protected resource or 401
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested labels

feature, enhancement

Poem

🐰 A server API hops into place,
Removing scattered session code with grace,
Now centralized and true,
Each framework gets its cue—
One getSession for the whole embrace! ✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title clearly and concisely summarizes the main change: introducing a server API through the createAuth function, which aligns with the primary modifications across all modified files.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/introduce-server-api

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🧹 Nitpick comments (5)
packages/core/src/index.ts (2)

67-78: Pin createAuth return type to AuthInstance.

Adding an explicit return type makes contract drift detectable at compile time.

♻️ Proposed typing update
-import type { AuthConfig } from "@/@types/index.ts"
+import type { AuthConfig, AuthInstance } from "@/@types/index.ts"
@@
-export const createAuth = (authConfig: AuthConfig) => {
+export const createAuth = (authConfig: AuthConfig): AuthInstance => {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/core/src/index.ts` around lines 67 - 78, The createAuth function
currently returns an inferred type; explicitly annotate its return as
AuthInstance to prevent contract drift—update the createAuth signature to return
AuthInstance (while keeping the body using createInternalConfig and createRouter
with signInAction, callbackAction, sessionAction, signOutAction,
csrfTokenAction) so the compiler enforces the public shape (handlers, jose,
server) matches the AuthInstance interface.

8-24: Re-export the new server/session types from the public barrel.

SessionResponse and AuthServerAPI are introduced but not exposed here, which makes consumer typing less discoverable.

♻️ Proposed export update
 export type {
     AuthConfig,
     AuthInstance,
+    AuthServerAPI,
     JoseInstance,
     Session,
+    SessionResponse,
     User,
     CookieConfig,
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/core/src/index.ts` around lines 8 - 24, The public barrel in
packages/core/src/index.ts currently re-exports many types but omits the new
server/session types; add SessionResponse and AuthServerAPI to the exported
types list so consumers can import them from the public package. Update the
export block that currently lists AuthConfig, AuthInstance, JoseInstance,
Session, User, etc., to include SessionResponse and AuthServerAPI (the unique
symbols to add) alongside the existing exports.
packages/core/src/context.ts (2)

33-33: Avoid parsing TRUSTED_ORIGINS twice.

Line 33 computes the same env array two times; caching it once makes this path clearer.

♻️ Proposed cleanup
+    const trustedOriginsEnv = getEnvArray("TRUSTED_ORIGINS")
@@
-        trustedOrigins: getEnvArray("TRUSTED_ORIGINS").length > 0 ? getEnvArray("TRUSTED_ORIGINS") : config?.trustedOrigins,
+        trustedOrigins: trustedOriginsEnv.length > 0 ? trustedOriginsEnv : config?.trustedOrigins,
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/core/src/context.ts` at line 33, The trustedOrigins initialization
currently calls getEnvArray("TRUSTED_ORIGINS") twice; store the result in a
local variable (e.g., const envTrusted = getEnvArray("TRUSTED_ORIGINS")) and use
that single cached value in the ternary expression that sets trustedOrigins
(fallback to config?.trustedOrigins) to avoid duplicate parsing and clarify
intent in the trustedOrigins assignment.

10-13: Rename cookieCofig before this typo spreads further.

Line 10 and Line 35 use cookieCofig; renaming to cookieConfig now will avoid avoidable churn across the new server API wiring.

♻️ Proposed rename in this file
 export type InternalContext = GlobalContext & {
-    cookieCofig: {
+    cookieConfig: {
         secure: CookieStoreConfig
         standard: CookieStoreConfig
     }
 }
@@
-        cookieCofig: { secure: secureCookieStore, standard: standardCookieStore },
+        cookieConfig: { secure: secureCookieStore, standard: standardCookieStore },

Also applies to: 35-35

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/core/src/context.ts` around lines 10 - 13, Rename the misspelled
property cookieCofig to cookieConfig throughout the module: update the
type/interface where cookieCofig is declared and any references (e.g., in the
context object and usages that read/write cookieCofig) so the symbol is
consistently cookieConfig; ensure related types CookieStoreConfig remain
unchanged and run the type-checker to catch remaining references to cookieCofig
(update imports/exports if the property is exposed).
packages/core/src/actions/session/session.ts (1)

12-17: Prefer direct branching over throw/catch for expected unauthenticated flow

Line 13–Line 15 uses exceptions for a non-exceptional branch and then handles it locally. A direct unauthorized return path is simpler and removes unnecessary control-flow indirection.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/core/src/actions/session/session.ts` around lines 12 - 17, Replace
the throw-based unauthenticated branch in the server.getSession handling with a
direct unauthorized return: after calling server.getSession(request) check
session.authenticated and if false return an unauthorized Response (e.g.,
Response.json({ error: "INVALID_JWT_TOKEN", message: "Session not authenticated"
}, { status: 401, headers: secureApiHeaders })) instead of throwing
AuthInternalError; leave the try/catch to handle real exceptions and remove the
local throw usage around AuthInternalError so control flow is direct and clearer
in the code that calls server.getSession and builds the Response.json.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/deno/src/index.ts`:
- Line 1: The code uses server.getSession but never imports server; add an
import for the exported server symbol from the module that defines it (the same
module that exports the server instance used elsewhere) and include it alongside
the existing handlers import so calls to server.getSession resolve correctly;
update the import statement that currently reads import { handlers } from
"./auth.ts" to also import server (e.g., import { handlers, server } from
<module-that-exports-server>) so server.getSession(...) works.
- Around line 9-10: The authorization check incorrectly tests the session object
itself (const session = await server.getSession(request); if (!session)) which
is always truthy; update the conditional to check the discriminant returned by
getSession instead (use if (!session.authenticated)) so unauthenticated requests
are rejected; adjust the branch that handles unauthorized access to respond with
the same 401/unauthorized behavior used in other integrations and keep the
variable name session and call site server.getSession(request) unchanged.

In `@apps/oak/src/middleware/with-auth.ts`:
- Line 21: The with-auth middleware references server.getSession(ctx.request)
but `server` is not declared or imported; fix by making the auth server
available to this module—either import the server instance used elsewhere (e.g.,
from your auth/server or auth/index export) or accept it as a parameter to the
withAuth function and use that parameter instead; update the call site to pass
the server if you change the signature, and ensure the code uses the correct
symbol (e.g., server.getSession or injectedServer.getSession) so the getSession
call is in-scope.

In `@apps/supabase/functions/auth/index.ts`:
- Line 15: The current check uses session.user which can throw when getSession()
returns null; change the authorization guard to use the discriminant
session?.authenticated (from the getSession() result) instead of accessing
session.user, and update any downstream logic in the auth handler in
apps/supabase/functions/auth/index.ts to rely on session when authenticated is
true (or handle null session) so you no longer dereference session.user when
session may be null.

In `@packages/core/src/server/create-server.ts`:
- Around line 6-12: getSession currently always reads the session cookie from
ctx.cookies.sessionToken.name (in createServerAPI -> getSession), which breaks
request-dependent cookie selection; update getSession to pick the cookie store
based on the incoming Request (use the same secure/standard selection logic used
elsewhere in your codebase) and then read the session token from that
request-specific cookie store instead of ctx.cookies.sessionToken.name so
HTTP/local requests use the correct cookie namespace.

---

Nitpick comments:
In `@packages/core/src/actions/session/session.ts`:
- Around line 12-17: Replace the throw-based unauthenticated branch in the
server.getSession handling with a direct unauthorized return: after calling
server.getSession(request) check session.authenticated and if false return an
unauthorized Response (e.g., Response.json({ error: "INVALID_JWT_TOKEN",
message: "Session not authenticated" }, { status: 401, headers: secureApiHeaders
})) instead of throwing AuthInternalError; leave the try/catch to handle real
exceptions and remove the local throw usage around AuthInternalError so control
flow is direct and clearer in the code that calls server.getSession and builds
the Response.json.

In `@packages/core/src/context.ts`:
- Line 33: The trustedOrigins initialization currently calls
getEnvArray("TRUSTED_ORIGINS") twice; store the result in a local variable
(e.g., const envTrusted = getEnvArray("TRUSTED_ORIGINS")) and use that single
cached value in the ternary expression that sets trustedOrigins (fallback to
config?.trustedOrigins) to avoid duplicate parsing and clarify intent in the
trustedOrigins assignment.
- Around line 10-13: Rename the misspelled property cookieCofig to cookieConfig
throughout the module: update the type/interface where cookieCofig is declared
and any references (e.g., in the context object and usages that read/write
cookieCofig) so the symbol is consistently cookieConfig; ensure related types
CookieStoreConfig remain unchanged and run the type-checker to catch remaining
references to cookieCofig (update imports/exports if the property is exposed).

In `@packages/core/src/index.ts`:
- Around line 67-78: The createAuth function currently returns an inferred type;
explicitly annotate its return as AuthInstance to prevent contract drift—update
the createAuth signature to return AuthInstance (while keeping the body using
createInternalConfig and createRouter with signInAction, callbackAction,
sessionAction, signOutAction, csrfTokenAction) so the compiler enforces the
public shape (handlers, jose, server) matches the AuthInstance interface.
- Around line 8-24: The public barrel in packages/core/src/index.ts currently
re-exports many types but omits the new server/session types; add
SessionResponse and AuthServerAPI to the exported types list so consumers can
import them from the public package. Update the export block that currently
lists AuthConfig, AuthInstance, JoseInstance, Session, User, etc., to include
SessionResponse and AuthServerAPI (the unique symbols to add) alongside the
existing exports.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cf0e175 and 8297c89.

📒 Files selected for processing (28)
  • apps/bun/src/auth.ts
  • apps/bun/src/index.ts
  • apps/bun/src/lib/get-session.ts
  • apps/deno/src/auth.ts
  • apps/deno/src/index.ts
  • apps/deno/src/lib/get-session.ts
  • apps/elysia/src/auth.ts
  • apps/elysia/src/lib/get-session.ts
  • apps/elysia/src/plugins/with-auth.ts
  • apps/express/src/auth.ts
  • apps/express/src/lib/get-session.ts
  • apps/express/src/lib/verify-session.ts
  • apps/hono/src/auth.ts
  • apps/hono/src/lib/get-session.ts
  • apps/hono/src/middleware/with-auth.ts
  • apps/oak/src/auth.ts
  • apps/oak/src/lib/get-session.ts
  • apps/oak/src/middleware/with-auth.ts
  • apps/supabase/functions/_shared/auth.ts
  • apps/supabase/functions/_shared/get-session.ts
  • apps/supabase/functions/auth/index.ts
  • packages/core/.vscode/settings.json
  • packages/core/src/@types/index.ts
  • packages/core/src/actions/session/session.ts
  • packages/core/src/context.ts
  • packages/core/src/index.ts
  • packages/core/src/server/create-server.ts
  • packages/core/test/actions/session/session.test.ts
💤 Files with no reviewable changes (7)
  • apps/bun/src/lib/get-session.ts
  • apps/deno/src/lib/get-session.ts
  • apps/supabase/functions/_shared/get-session.ts
  • apps/elysia/src/lib/get-session.ts
  • apps/oak/src/lib/get-session.ts
  • apps/express/src/lib/get-session.ts
  • apps/hono/src/lib/get-session.ts

Comment on lines +6 to +12
export const createServerAPI = (ctx: Omit<GlobalContext, "server">) => {
return {
getSession: async (request: Request): Promise<SessionResponse> => {
const { cookies, jose, logger } = ctx
try {
const session = getCookie(request, cookies.sessionToken.name)
const decoded = await jose.decodeJWT(session)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

getSession is using a static cookie store, which can break standard-cookie session reads.

Line 11 always uses ctx.cookies.sessionToken.name. Since secure/standard selection is request-dependent (see packages/core/src/index.ts Line 38), server.getSession(request) can return unauthenticated for valid HTTP/local sessions.

🐛 Proposed fix (select cookie store per request)
 import { getCookie } from "../cookie.ts"
-import { getErrorName, toISOString } from "../utils.ts"
-import type { GlobalContext } from "@aura-stack/router"
+import { getErrorName, toISOString, useSecureCookies } from "../utils.ts"
+import type { InternalContext } from "../context.ts"
 import type { JWTStandardClaims, SessionResponse, User } from "@/@types/index.ts"

-export const createServerAPI = (ctx: Omit<GlobalContext, "server">) => {
+export const createServerAPI = (ctx: InternalContext) => {
     return {
         getSession: async (request: Request): Promise<SessionResponse> => {
-            const { cookies, jose, logger } = ctx
+            const { jose, logger } = ctx
+            const cookies = useSecureCookies(request, ctx.trustedProxyHeaders)
+                ? ctx.cookieCofig.secure
+                : ctx.cookieCofig.standard
             try {
                 const session = getCookie(request, cookies.sessionToken.name)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/core/src/server/create-server.ts` around lines 6 - 12, getSession
currently always reads the session cookie from ctx.cookies.sessionToken.name (in
createServerAPI -> getSession), which breaks request-dependent cookie selection;
update getSession to pick the cookie store based on the incoming Request (use
the same secure/standard selection logic used elsewhere in your codebase) and
then read the session token from that request-specific cookie store instead of
ctx.cookies.sessionToken.name so HTTP/local requests use the correct cookie
namespace.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant