diff --git a/express/app.ts b/express/app.ts index 8349013..14da28e 100644 --- a/express/app.ts +++ b/express/app.ts @@ -59,7 +59,7 @@ routes.forEach((route: Route, _idx: number, _allRoutes: Route[]) => { console.log("request.originalUrl", request.originalUrl); // Authenticate the request - const user = await services.auth.validateRequest(request); + const auth = await services.auth.validateRequest(request); const req: Call = { pattern: route.path, @@ -67,7 +67,8 @@ routes.forEach((route: Route, _idx: number, _allRoutes: Route[]) => { method, parameters: { one: 1, two: 2 }, request, - user, + user: auth.user, + session: auth.session, }; try { diff --git a/express/auth/index.ts b/express/auth/index.ts index 35f06a9..d68d1fc 100644 --- a/express/auth/index.ts +++ b/express/auth/index.ts @@ -7,7 +7,7 @@ // Import authRoutes directly from "./auth/routes" instead. export { hashPassword, verifyPassword } from "./password"; -export { AuthService } from "./service"; +export { AuthService, type AuthResult } from "./service"; export { type AuthStore, InMemoryAuthStore } from "./store"; export { generateToken, hashToken, SESSION_COOKIE_NAME } from "./token"; export * from "./types"; diff --git a/express/auth/service.ts b/express/auth/service.ts index 7064173..f5deb29 100644 --- a/express/auth/service.ts +++ b/express/auth/service.ts @@ -12,7 +12,7 @@ import { parseAuthorizationHeader, SESSION_COOKIE_NAME, } from "./token"; -import { type TokenId, tokenLifetimes } from "./types"; +import { type SessionData, type TokenId, tokenLifetimes } from "./types"; type LoginResult = | { success: true; token: string; user: User } @@ -24,6 +24,11 @@ type RegisterResult = type SimpleResult = { success: true } | { success: false; error: string }; +// Result of validating a request/token - contains both user and session +export type AuthResult = + | { authenticated: true; user: User; session: SessionData } + | { authenticated: false; user: typeof AnonymousUser; session: null }; + export class AuthService { constructor(private store: AuthStore) {} @@ -68,7 +73,7 @@ export class AuthService { // === Session Validation === - async validateRequest(request: ExpressRequest): Promise { + async validateRequest(request: ExpressRequest): Promise { // Try cookie first (for web requests) let token = this.extractCookieToken(request); @@ -78,33 +83,33 @@ export class AuthService { } if (!token) { - return AnonymousUser; + return { authenticated: false, user: AnonymousUser, session: null }; } return this.validateToken(token); } - async validateToken(token: string): Promise { + async validateToken(token: string): Promise { const tokenId = hashToken(token) as TokenId; const session = await this.store.getSession(tokenId); if (!session) { - return AnonymousUser; + return { authenticated: false, user: AnonymousUser, session: null }; } if (session.tokenType !== "session") { - return AnonymousUser; + return { authenticated: false, user: AnonymousUser, session: null }; } const user = await this.store.getUserById(session.userId as UserId); if (!user || !user.isActive()) { - return AnonymousUser; + return { authenticated: false, user: AnonymousUser, session: null }; } // Update last used (fire and forget) this.store.updateLastUsed(tokenId).catch(() => {}); - return user; + return { authenticated: true, user, session }; } private extractCookieToken(request: ExpressRequest): string | null { diff --git a/express/types.ts b/express/types.ts index d595c48..a1ed455 100644 --- a/express/types.ts +++ b/express/types.ts @@ -8,6 +8,7 @@ import { } from "express"; import type { MatchFunction } from "path-to-regexp"; import { z } from "zod"; +import type { SessionData } from "./auth/types"; import { type ContentType, contentTypes } from "./content-types"; import { type HttpCode, httpCodes } from "./http-codes"; import { @@ -39,6 +40,7 @@ export type Call = { parameters: object; request: ExpressRequest; user: MaybeUser; + session: SessionData | null; }; export type InternalHandler = (req: ExpressRequest) => Promise;