@startsimpli/auth 0.4.5 → 0.4.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@startsimpli/auth",
3
- "version": "0.4.5",
3
+ "version": "0.4.6",
4
4
  "description": "Shared authentication package for StartSimpli Next.js apps",
5
5
  "main": "./src/index.ts",
6
6
  "types": "./src/index.ts",
@@ -85,18 +85,15 @@ function makeJwt(payload: object): string {
85
85
 
86
86
  const VALID_TOKEN = makeJwt({ exp: Math.floor(Date.now() / 1000) + 3600, user_id: '1' });
87
87
 
88
- describe('CSRF token on signin/register', () => {
88
+ describe('CSRF not required for signin/register (endpoints are @csrf_exempt)', () => {
89
89
  beforeEach(() => {
90
90
  vi.clearAllMocks();
91
91
  mockSessionStorage.clear();
92
92
  mockLocalStorage.clear();
93
93
  });
94
94
 
95
- it('signInWithCredentials sends X-CSRFToken header', async () => {
96
- mockFetch.mockImplementation((url: string) => {
97
- if (url.includes('/csrf/')) {
98
- return Promise.resolve({ ok: true });
99
- }
95
+ it('signInWithCredentials does not fetch or send CSRF token', async () => {
96
+ mockFetch.mockImplementation(() => {
100
97
  return Promise.resolve({
101
98
  ok: true,
102
99
  status: 200,
@@ -106,20 +103,23 @@ describe('CSRF token on signin/register', () => {
106
103
 
107
104
  await signInWithCredentials('test@test.com', 'password');
108
105
 
109
- // Find the token endpoint call (not the csrf call)
106
+ // Should NOT call the CSRF endpoint
107
+ const csrfCall = mockFetch.mock.calls.find(
108
+ (c: unknown[]) => typeof c[0] === 'string' && (c[0] as string).includes('/csrf/')
109
+ );
110
+ expect(csrfCall).toBeUndefined();
111
+
112
+ // Token endpoint call should not include X-CSRFToken header
110
113
  const tokenCall = mockFetch.mock.calls.find(
111
114
  (c: unknown[]) => typeof c[0] === 'string' && (c[0] as string).includes('/auth/token/') && !(c[0] as string).includes('csrf') && !(c[0] as string).includes('refresh')
112
115
  );
113
116
  expect(tokenCall).toBeDefined();
114
117
  const headers = tokenCall![1]?.headers;
115
- expect(headers['X-CSRFToken']).toBe('test-csrf');
118
+ expect(headers['X-CSRFToken']).toBeUndefined();
116
119
  });
117
120
 
118
- it('registerAccount sends X-CSRFToken header', async () => {
119
- mockFetch.mockImplementation((url: string) => {
120
- if (url.includes('/csrf/')) {
121
- return Promise.resolve({ ok: true });
122
- }
121
+ it('registerAccount does not fetch or send CSRF token', async () => {
122
+ mockFetch.mockImplementation(() => {
123
123
  return Promise.resolve({
124
124
  ok: true,
125
125
  status: 200,
@@ -133,12 +133,18 @@ describe('CSRF token on signin/register', () => {
133
133
  passwordConfirm: 'securepassword',
134
134
  });
135
135
 
136
+ // Should NOT call the CSRF endpoint
137
+ const csrfCall = mockFetch.mock.calls.find(
138
+ (c: unknown[]) => typeof c[0] === 'string' && (c[0] as string).includes('/csrf/')
139
+ );
140
+ expect(csrfCall).toBeUndefined();
141
+
136
142
  const registerCall = mockFetch.mock.calls.find(
137
143
  (c: unknown[]) => typeof c[0] === 'string' && (c[0] as string).includes('/auth/register/')
138
144
  );
139
145
  expect(registerCall).toBeDefined();
140
146
  const headers = registerCall![1]?.headers;
141
- expect(headers['X-CSRFToken']).toBe('test-csrf');
147
+ expect(headers['X-CSRFToken']).toBeUndefined();
142
148
  });
143
149
  });
144
150
 
@@ -243,13 +243,11 @@ function parseAuthResponse(data: unknown): { access?: string; user?: AuthUser }
243
243
  // --- Auth functions ---
244
244
 
245
245
  export async function signInWithCredentials(email: string, password: string) {
246
- await fetchCsrfToken();
247
- const csrfToken = getCsrfToken();
246
+ // No CSRF needed — Django's /auth/token/ is @csrf_exempt (JWT endpoint)
248
247
  const response = await fetchWithTimeout(resolveAuthUrl(AUTH_PATHS.TOKEN), {
249
248
  method: 'POST',
250
249
  headers: {
251
250
  'Content-Type': 'application/json',
252
- ...(csrfToken ? { 'X-CSRFToken': csrfToken } : {}),
253
251
  },
254
252
  credentials: 'include',
255
253
  body: JSON.stringify({ email, password }),
@@ -286,13 +284,11 @@ export async function registerAccount(payload: {
286
284
  const [firstFromName, ...rest] = rawName ? rawName.split(/\s+/) : [];
287
285
  const lastFromName = rest.length ? rest.join(' ') : undefined;
288
286
 
289
- await fetchCsrfToken();
290
- const csrfToken = getCsrfToken();
287
+ // No CSRF needed — Django's /auth/register/ is @csrf_exempt
291
288
  const response = await fetchWithTimeout(resolveAuthUrl(AUTH_PATHS.REGISTER), {
292
289
  method: 'POST',
293
290
  headers: {
294
291
  'Content-Type': 'application/json',
295
- ...(csrfToken ? { 'X-CSRFToken': csrfToken } : {}),
296
292
  },
297
293
  credentials: 'include',
298
294
  body: JSON.stringify({