fix(auth): preserve raw BetterAuth cookie token for session lookup
All checks were successful
ci/woodpecker/push/api Pipeline was successful
All checks were successful
ci/woodpecker/push/api Pipeline was successful
This commit is contained in:
@@ -426,6 +426,21 @@ describe("AuthService", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("should preserve raw cookie token value without URL re-encoding", async () => {
|
||||
const auth = service.getAuth();
|
||||
const mockGetSession = vi.fn().mockResolvedValue(mockSessionData);
|
||||
auth.api = { getSession: mockGetSession } as any;
|
||||
|
||||
const result = await service.verifySession("tok/with+=chars=");
|
||||
|
||||
expect(result).toEqual(mockSessionData);
|
||||
expect(mockGetSession).toHaveBeenCalledWith({
|
||||
headers: {
|
||||
cookie: "__Secure-better-auth.session_token=tok/with+=chars=",
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it("should fall back to Authorization header when cookie-based lookups miss", async () => {
|
||||
const auth = service.getAuth();
|
||||
const mockGetSession = vi
|
||||
|
||||
@@ -150,22 +150,20 @@ export class AuthService {
|
||||
}
|
||||
|
||||
private buildSessionHeaderCandidates(token: string): SessionHeaderCandidate[] {
|
||||
const encodedToken = encodeURIComponent(token);
|
||||
|
||||
return [
|
||||
{
|
||||
headers: {
|
||||
cookie: `__Secure-better-auth.session_token=${encodedToken}`,
|
||||
cookie: `__Secure-better-auth.session_token=${token}`,
|
||||
},
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
cookie: `better-auth.session_token=${encodedToken}`,
|
||||
cookie: `better-auth.session_token=${token}`,
|
||||
},
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
cookie: `__Host-better-auth.session_token=${encodedToken}`,
|
||||
cookie: `__Host-better-auth.session_token=${token}`,
|
||||
},
|
||||
},
|
||||
{
|
||||
|
||||
@@ -112,3 +112,42 @@ Completed items:
|
||||
Remaining step (requires deploy):
|
||||
|
||||
- Redeploy API with this patch and rerun live Playwright flow on `app.mosaicstack.dev` to confirm `/auth/session` returns `200` after callback.
|
||||
|
||||
## Playwright Re-Check (2026-02-19, later run)
|
||||
|
||||
Live flow evidence after previous deploy attempt:
|
||||
|
||||
1. OAuth callback succeeds:
|
||||
- `GET https://api.mosaicstack.dev/auth/oauth2/callback/authentik?code=...&state=...` -> `302`
|
||||
- Redirect target observed: `https://app.mosaicstack.dev/`
|
||||
- Browser cookie jar includes:
|
||||
- `__Secure-better-auth.session_token` on `api.mosaicstack.dev` (HttpOnly, Secure, SameSite=Lax)
|
||||
|
||||
2. Session bootstrap still fails immediately:
|
||||
- `GET https://api.mosaicstack.dev/auth/session` -> `500`
|
||||
- Response body shape:
|
||||
- `{"success":false,"message":"An unexpected error occurred","errorId":"...","path":"/auth/session","statusCode":500}`
|
||||
- Web app returns to login because session fetch fails.
|
||||
|
||||
3. Frontend version mismatch observed:
|
||||
- Live `POST /auth/sign-in/oauth2` response from login flow still shows callback URL pointing to `/dashboard`.
|
||||
- Current repository login page uses callback URL `/`.
|
||||
- This indicates deployed web image is older than current `develop` code (or stale image tag in runtime).
|
||||
|
||||
## Additional Code Fix Applied Locally (pending push/deploy)
|
||||
|
||||
Refined cookie candidate construction in API session verification:
|
||||
|
||||
- File: `apps/api/src/auth/auth.service.ts`
|
||||
- Removed URL-encoding of session token when constructing cookie headers.
|
||||
- Cookie candidates now pass raw token value exactly as extracted from incoming cookie.
|
||||
|
||||
Why:
|
||||
|
||||
- BetterAuth cookie tokens can contain characters like `/`, `+`, and `=`.
|
||||
- Re-encoding these values can mutate token bytes and cause lookup/parse failures.
|
||||
|
||||
Regression test added:
|
||||
|
||||
- File: `apps/api/src/auth/auth.service.spec.ts`
|
||||
- `should preserve raw cookie token value without URL re-encoding`
|
||||
|
||||
Reference in New Issue
Block a user