@startsimpli/auth 0.4.28 → 0.4.29

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.28",
3
+ "version": "0.4.29",
4
4
  "description": "Shared authentication package for StartSimpli Next.js apps",
5
5
  "main": "./src/index.ts",
6
6
  "types": "./src/index.ts",
@@ -119,6 +119,54 @@ describe('CSRF not required for signin/register (endpoints are @csrf_exempt)', (
119
119
  expect(headers['X-CSRFToken']).toBeUndefined();
120
120
  });
121
121
 
122
+ it('signInWithCredentials threads the login target (app) into the body when provided (qxv2.5)', async () => {
123
+ mockFetch.mockImplementation(() =>
124
+ Promise.resolve({
125
+ ok: true,
126
+ status: 200,
127
+ json: async () => ({ access: VALID_TOKEN, user: { id: '1', email: 'a@b.com' } }),
128
+ }),
129
+ );
130
+
131
+ await signInWithCredentials('test@test.com', 'password', 'foundry');
132
+
133
+ const tokenCall = mockFetch.mock.calls.find(
134
+ (c: unknown[]) =>
135
+ typeof c[0] === 'string' &&
136
+ (c[0] as string).includes('/auth/token/') &&
137
+ !(c[0] as string).includes('refresh'),
138
+ );
139
+ expect(tokenCall).toBeDefined();
140
+ expect(JSON.parse(tokenCall![1]!.body as string)).toEqual({
141
+ email: 'test@test.com',
142
+ password: 'password',
143
+ app: 'foundry',
144
+ });
145
+ });
146
+
147
+ it('signInWithCredentials omits app from the body when not provided (qxv2.5)', async () => {
148
+ mockFetch.mockImplementation(() =>
149
+ Promise.resolve({
150
+ ok: true,
151
+ status: 200,
152
+ json: async () => ({ access: VALID_TOKEN, user: { id: '1', email: 'a@b.com' } }),
153
+ }),
154
+ );
155
+
156
+ await signInWithCredentials('test@test.com', 'password');
157
+
158
+ const tokenCall = mockFetch.mock.calls.find(
159
+ (c: unknown[]) =>
160
+ typeof c[0] === 'string' &&
161
+ (c[0] as string).includes('/auth/token/') &&
162
+ !(c[0] as string).includes('refresh'),
163
+ );
164
+ expect(JSON.parse(tokenCall![1]!.body as string)).toEqual({
165
+ email: 'test@test.com',
166
+ password: 'password',
167
+ });
168
+ });
169
+
122
170
  it('registerAccount does not fetch or send CSRF token', async () => {
123
171
  mockFetch.mockImplementation(() => {
124
172
  return Promise.resolve({
@@ -330,7 +330,10 @@ function parseAuthResponse(data: unknown): { access?: string; user?: AuthUser }
330
330
 
331
331
  // --- Auth functions ---
332
332
 
333
- export async function signInWithCredentials(email: string, password: string) {
333
+ export async function signInWithCredentials(email: string, password: string, app?: string) {
334
+ // `app` is the login target (qxv2.5): the central mint scopes the token's
335
+ // audience to it (control plane => first-party for a foundry owner; tenant =>
336
+ // tenant aud). Server-validated; omitted => current home-org behavior.
334
337
  // No CSRF needed — Django's /auth/token/ is @csrf_exempt (JWT endpoint)
335
338
  const response = await fetchWithTimeout(resolveAuthUrl(AUTH_PATHS.TOKEN), {
336
339
  method: 'POST',
@@ -338,7 +341,7 @@ export async function signInWithCredentials(email: string, password: string) {
338
341
  'Content-Type': 'application/json',
339
342
  },
340
343
  credentials: 'include',
341
- body: JSON.stringify({ email, password }),
344
+ body: JSON.stringify(app ? { email, password, app } : { email, password }),
342
345
  });
343
346
 
344
347
  const data = await response.json().catch(() => ({}));