Skip to content

Commit 207dfad

Browse files
committed
pass resolved config to CookieSessionStorage
1 parent ef86d09 commit 207dfad

File tree

2 files changed

+62
-83
lines changed

2 files changed

+62
-83
lines changed

src/core/session/CookieSessionStorage.spec.ts

Lines changed: 45 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,18 @@
11
import { CookieSessionStorage } from './CookieSessionStorage.js';
2-
3-
// Mock config provider
4-
const createMockConfig = (overrides: Record<string, any> = {}) => ({
5-
getValue: (key: string) => {
6-
const defaults = {
7-
cookieName: 'wos-session',
8-
cookieSameSite: 'lax',
9-
apiHttps: true,
10-
cookieMaxAge: 60 * 60 * 24 * 400,
11-
cookieDomain: undefined,
12-
};
13-
return overrides[key] ?? defaults[key as keyof typeof defaults];
14-
},
2+
import type { AuthKitConfig } from '../config/types.js';
3+
4+
// Mock config
5+
const createMockConfig = (overrides: Partial<AuthKitConfig> = {}): AuthKitConfig => ({
6+
clientId: 'test-client-id',
7+
apiKey: 'test-api-key',
8+
redirectUri: 'https://example.com/callback',
9+
cookiePassword: 'test-password-that-is-32-chars-long!!',
10+
cookieName: 'wos-session',
11+
cookieSameSite: 'lax',
12+
apiHttps: true,
13+
cookieMaxAge: 60 * 60 * 24 * 400,
14+
cookieDomain: undefined,
15+
...overrides,
1516
});
1617

1718
// Concrete implementation for testing the abstract class
@@ -24,7 +25,7 @@ class TestCookieSessionStorage extends CookieSessionStorage<string, string> {
2425
describe('CookieSessionStorage', () => {
2526
describe('constructor', () => {
2627
it('sets default cookie configuration', () => {
27-
const storage = new TestCookieSessionStorage(createMockConfig() as any);
28+
const storage = new TestCookieSessionStorage(createMockConfig());
2829

2930
expect(storage['cookieName']).toBe('wos-session');
3031
expect(storage['cookieOptions']).toEqual({
@@ -39,87 +40,69 @@ describe('CookieSessionStorage', () => {
3940

4041
it('uses custom cookie name from config', () => {
4142
const config = createMockConfig({ cookieName: 'custom-session' });
42-
const storage = new TestCookieSessionStorage(config as any);
43+
const storage = new TestCookieSessionStorage(config);
4344

4445
expect(storage['cookieName']).toBe('custom-session');
4546
});
4647

47-
it('falls back to default cookie name when config returns falsy', () => {
48-
const config = createMockConfig({ cookieName: '' });
49-
const storage = new TestCookieSessionStorage(config as any);
50-
51-
expect(storage['cookieName']).toBe('wos_session');
52-
});
53-
5448
it('uses custom sameSite setting', () => {
5549
const config = createMockConfig({ cookieSameSite: 'strict' });
56-
const storage = new TestCookieSessionStorage(config as any);
50+
const storage = new TestCookieSessionStorage(config);
5751

5852
expect(storage['cookieOptions'].sameSite).toBe('strict');
5953
});
6054

61-
it('uses custom security settings', () => {
62-
const config = createMockConfig({ apiHttps: false });
63-
const storage = new TestCookieSessionStorage(config as any);
55+
it('infers secure=false from http redirectUri', () => {
56+
const config = createMockConfig({ redirectUri: 'http://localhost:3000/callback' });
57+
const storage = new TestCookieSessionStorage(config);
6458

6559
expect(storage['cookieOptions'].secure).toBe(false);
6660
});
6761

62+
it('infers secure=true from https redirectUri', () => {
63+
const config = createMockConfig({ redirectUri: 'https://example.com/callback' });
64+
const storage = new TestCookieSessionStorage(config);
65+
66+
expect(storage['cookieOptions'].secure).toBe(true);
67+
});
68+
69+
it('forces secure=true when sameSite is none', () => {
70+
const config = createMockConfig({
71+
cookieSameSite: 'none',
72+
redirectUri: 'http://localhost:3000/callback',
73+
});
74+
const storage = new TestCookieSessionStorage(config);
75+
76+
expect(storage['cookieOptions'].secure).toBe(true);
77+
});
78+
6879
it('uses custom max age', () => {
6980
const customMaxAge = 60 * 60 * 24; // 1 day
7081
const config = createMockConfig({ cookieMaxAge: customMaxAge });
71-
const storage = new TestCookieSessionStorage(config as any);
82+
const storage = new TestCookieSessionStorage(config);
7283

7384
expect(storage['cookieOptions'].maxAge).toBe(customMaxAge);
7485
});
7586

76-
it('uses default max age when config returns null', () => {
77-
const config = createMockConfig({ cookieMaxAge: null });
78-
const storage = new TestCookieSessionStorage(config as any);
79-
80-
expect(storage['cookieOptions'].maxAge).toBe(60 * 60 * 24 * 400);
81-
});
82-
8387
it('sets custom cookie domain', () => {
8488
const config = createMockConfig({ cookieDomain: '.example.com' });
85-
const storage = new TestCookieSessionStorage(config as any);
89+
const storage = new TestCookieSessionStorage(config);
8690

8791
expect(storage['cookieOptions'].domain).toBe('.example.com');
8892
});
89-
90-
it('uses all default fallbacks', () => {
91-
const config = createMockConfig({
92-
cookieName: '',
93-
cookieSameSite: null,
94-
apiHttps: null,
95-
cookieMaxAge: null,
96-
cookieDomain: null,
97-
});
98-
const storage = new TestCookieSessionStorage(config as any);
99-
100-
expect(storage['cookieName']).toBe('wos_session');
101-
expect(storage['cookieOptions']).toEqual({
102-
path: '/',
103-
httpOnly: true,
104-
sameSite: 'lax',
105-
secure: true,
106-
maxAge: 60 * 60 * 24 * 400,
107-
domain: undefined,
108-
});
109-
});
11093
});
11194

11295
describe('abstract methods', () => {
11396
it('implements SessionStorage interface', () => {
114-
const storage = new TestCookieSessionStorage(createMockConfig() as any);
97+
const storage = new TestCookieSessionStorage(createMockConfig());
11598

11699
expect(typeof storage.getSession).toBe('function');
117100
expect(typeof storage.saveSession).toBe('function');
118101
expect(typeof storage.clearSession).toBe('function');
119102
});
120103

121104
it('concrete implementation works', async () => {
122-
const storage = new TestCookieSessionStorage(createMockConfig() as any);
105+
const storage = new TestCookieSessionStorage(createMockConfig());
123106

124107
const session = await storage.getSession();
125108
expect(session).toBeNull();
@@ -137,14 +120,14 @@ describe('CookieSessionStorage', () => {
137120
describe('buildSetCookie', () => {
138121
it('capitalizes SameSite values for Safari compatibility', async () => {
139122
const testCases = [
140-
{ input: 'lax', expected: 'SameSite=Lax' },
141-
{ input: 'strict', expected: 'SameSite=Strict' },
142-
{ input: 'none', expected: 'SameSite=None' },
123+
{ input: 'lax' as const, expected: 'SameSite=Lax' },
124+
{ input: 'strict' as const, expected: 'SameSite=Strict' },
125+
{ input: 'none' as const, expected: 'SameSite=None' },
143126
];
144127

145128
for (const { input, expected } of testCases) {
146129
const config = createMockConfig({ cookieSameSite: input });
147-
const storage = new TestCookieSessionStorage(config as any);
130+
const storage = new TestCookieSessionStorage(config);
148131
const result = await storage.saveSession(undefined, 'test-data');
149132
expect(result.headers?.['Set-Cookie']).toContain(expected);
150133
}

src/core/session/CookieSessionStorage.ts

Lines changed: 17 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { ConfigurationProvider } from '../config/ConfigurationProvider.js';
1+
import type { AuthKitConfig } from '../config/types.js';
22
import type { HeadersBag, SessionStorage } from './types.js';
33

44
export interface CookieOptions {
@@ -18,35 +18,31 @@ export abstract class CookieSessionStorage<TRequest, TResponse>
1818
{
1919
protected cookieName: string;
2020
protected readonly cookieOptions: CookieOptions;
21-
protected config: ConfigurationProvider;
2221

23-
constructor(config: ConfigurationProvider) {
24-
this.config = config;
25-
this.cookieName = config.getValue('cookieName') || 'wos_session';
22+
constructor(config: AuthKitConfig) {
23+
this.cookieName = config.cookieName ?? 'wos_session';
2624

27-
// Infer secure flag from redirectUri if not explicitly set
28-
let secure = config.getValue('apiHttps');
29-
if (secure === undefined) {
30-
const redirectUri = config.getValue('redirectUri');
31-
if (redirectUri) {
32-
try {
33-
const url = new URL(redirectUri);
34-
secure = url.protocol === 'https:';
35-
} catch {
36-
secure = true; // Default to secure if URL parsing fails
37-
}
38-
} else {
39-
secure = true; // Default to secure if no redirectUri
25+
const sameSite = config.cookieSameSite ?? 'lax';
26+
27+
// Infer secure flag from redirectUri protocol
28+
// sameSite='none' requires secure=true (browser requirement)
29+
let secure = true;
30+
if (sameSite.toLowerCase() !== 'none') {
31+
try {
32+
const url = new URL(config.redirectUri);
33+
secure = url.protocol === 'https:';
34+
} catch {
35+
// Invalid URL - keep secure=true (safer default)
4036
}
4137
}
4238

4339
this.cookieOptions = {
4440
path: '/',
4541
httpOnly: true,
46-
sameSite: config.getValue('cookieSameSite') ?? 'lax',
42+
sameSite,
4743
secure,
48-
maxAge: config.getValue('cookieMaxAge') || 60 * 60 * 24 * 400, // 400 days
49-
domain: config.getValue('cookieDomain'),
44+
maxAge: config.cookieMaxAge ?? 60 * 60 * 24 * 400, // 400 days
45+
domain: config.cookieDomain,
5046
};
5147
}
5248

0 commit comments

Comments
 (0)