@authrim/sveltekit 0.1.2 → 0.1.4

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.
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/lib/client.ts"],"names":[],"mappings":"AAAA;;GAEG;AAYH,OAAO,KAAK,EACV,aAAa,EACb,aAAa,EAgBd,MAAM,YAAY,CAAC;AAmEpB;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,aAAa,GACpB,OAAO,CAAC,aAAa,CAAC,CAkbxB"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/lib/client.ts"],"names":[],"mappings":"AAAA;;GAEG;AAYH,OAAO,KAAK,EACV,aAAa,EACb,aAAa,EAgBd,MAAM,YAAY,CAAC;AAmEpB;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,aAAa,GACpB,OAAO,CAAC,aAAa,CAAC,CAsbxB"}
package/dist/client.js CHANGED
@@ -80,8 +80,8 @@ export async function createAuthrim(config) {
80
80
  http,
81
81
  });
82
82
  // Token exchange callback
83
- const exchangeToken = async (authCode, codeVerifier) => {
84
- return sessionManager.exchangeToken(authCode, codeVerifier);
83
+ const exchangeToken = async (authCode, codeVerifier, providerId) => {
84
+ return sessionManager.exchangeToken(authCode, codeVerifier, undefined, providerId);
85
85
  };
86
86
  // Create Direct Auth implementations
87
87
  const passkeyImpl = new PasskeyAuthImpl({
@@ -25,7 +25,7 @@ export declare class SessionAuthImpl implements SessionAuth {
25
25
  getUser(): Promise<User | null>;
26
26
  validate(): Promise<boolean>;
27
27
  logout(options?: DirectAuthLogoutOptions): Promise<void>;
28
- exchangeToken(authCode: string, codeVerifier: string, requestRefreshToken?: boolean): Promise<{
28
+ exchangeToken(authCode: string, codeVerifier: string, requestRefreshToken?: boolean, providerId?: string): Promise<{
29
29
  session?: Session;
30
30
  user?: User;
31
31
  }>;
@@ -1 +1 @@
1
- {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/lib/direct-auth/session.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAEL,KAAK,WAAW,EAChB,KAAK,OAAO,EACZ,KAAK,uBAAuB,EAG5B,KAAK,IAAI,EACV,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAU9D,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,iBAAiB,CAAC;CACzB;AAaD,qBAAa,eAAgB,YAAW,WAAW;IACjD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAoB;IACzC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,aAAa,CAAwB;IAC7C,OAAO,CAAC,UAAU,CAAqB;IACvC,OAAO,CAAC,kBAAkB,CAAa;IACvC,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAS;gBAE/B,OAAO,EAAE,qBAAqB;IAO1C,OAAO,CAAC,cAAc;IAStB,OAAO,CAAC,UAAU;IASlB,OAAO,CAAC,iBAAiB;IASnB,GAAG,IAAI,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC;IAyC9B,OAAO,IAAI,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC;IAS/B,QAAQ,IAAI,OAAO,CAAC,OAAO,CAAC;IAY5B,MAAM,CAAC,OAAO,CAAC,EAAE,uBAAuB,GAAG,OAAO,CAAC,IAAI,CAAC;IAqCxD,aAAa,CACjB,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,MAAM,EACpB,mBAAmB,CAAC,EAAE,OAAO,GAC5B,OAAO,CAAC;QAAE,OAAO,CAAC,EAAE,OAAO,CAAC;QAAC,IAAI,CAAC,EAAE,IAAI,CAAA;KAAE,CAAC;IAgE9C;;;;;;;;;;OAUG;IACG,OAAO,IAAI,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC;IAKlC,eAAe,IAAI,OAAO,CAAC,OAAO,CAAC;IAUzC,UAAU,IAAI,IAAI;IAMlB,QAAQ,IAAI,MAAM,GAAG,IAAI;CAG1B"}
1
+ {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/lib/direct-auth/session.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAEL,KAAK,WAAW,EAChB,KAAK,OAAO,EACZ,KAAK,uBAAuB,EAG5B,KAAK,IAAI,EACV,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAU9D,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,iBAAiB,CAAC;CACzB;AAaD,qBAAa,eAAgB,YAAW,WAAW;IACjD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAoB;IACzC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,aAAa,CAAwB;IAC7C,OAAO,CAAC,UAAU,CAAqB;IACvC,OAAO,CAAC,kBAAkB,CAAa;IACvC,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAS;gBAE/B,OAAO,EAAE,qBAAqB;IAO1C,OAAO,CAAC,cAAc;IAStB,OAAO,CAAC,UAAU;IASlB,OAAO,CAAC,iBAAiB;IASnB,GAAG,IAAI,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC;IAyC9B,OAAO,IAAI,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC;IAS/B,QAAQ,IAAI,OAAO,CAAC,OAAO,CAAC;IAY5B,MAAM,CAAC,OAAO,CAAC,EAAE,uBAAuB,GAAG,OAAO,CAAC,IAAI,CAAC;IAqCxD,aAAa,CACjB,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,MAAM,EACpB,mBAAmB,CAAC,EAAE,OAAO,EAC7B,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC;QAAE,OAAO,CAAC,EAAE,OAAO,CAAC;QAAC,IAAI,CAAC,EAAE,IAAI,CAAA;KAAE,CAAC;IAmE9C;;;;;;;;;;OAUG;IACG,OAAO,IAAI,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC;IAKlC,eAAe,IAAI,OAAO,CAAC,OAAO,CAAC;IAUzC,UAAU,IAAI,IAAI;IAMlB,QAAQ,IAAI,MAAM,GAAG,IAAI;CAG1B"}
@@ -144,7 +144,7 @@ export class SessionAuthImpl {
144
144
  window.location.href = options.redirectUri;
145
145
  }
146
146
  }
147
- async exchangeToken(authCode, codeVerifier, requestRefreshToken) {
147
+ async exchangeToken(authCode, codeVerifier, requestRefreshToken, providerId) {
148
148
  const request = {
149
149
  grant_type: 'authorization_code',
150
150
  code: authCode,
@@ -152,6 +152,9 @@ export class SessionAuthImpl {
152
152
  code_verifier: codeVerifier,
153
153
  request_refresh_token: requestRefreshToken,
154
154
  };
155
+ if (providerId) {
156
+ request.provider_id = providerId;
157
+ }
155
158
  const response = await this.http.fetch(`${this.issuer}${ENDPOINTS.TOKEN}`, {
156
159
  method: 'POST',
157
160
  headers: { 'Content-Type': 'application/json' },
@@ -7,7 +7,7 @@ export interface SocialAuthOptions {
7
7
  clientId: string;
8
8
  crypto: CryptoProvider;
9
9
  storage: AuthrimStorage;
10
- exchangeToken: (authCode: string, codeVerifier: string) => Promise<{
10
+ exchangeToken: (authCode: string, codeVerifier: string, providerId?: string) => Promise<{
11
11
  session?: Session;
12
12
  user?: User;
13
13
  }>;
@@ -1 +1 @@
1
- {"version":3,"file":"social.d.ts","sourceRoot":"","sources":["../../src/lib/direct-auth/social.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAGL,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,KAAK,UAAU,EACf,KAAK,cAAc,EACnB,KAAK,kBAAkB,EACvB,KAAK,UAAU,EACf,KAAK,OAAO,EACZ,KAAK,IAAI,EACV,MAAM,eAAe,CAAC;AAwGvB,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,cAAc,CAAC;IACvB,OAAO,EAAE,cAAc,CAAC;IACxB,aAAa,EAAE,CACb,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,MAAM,KACjB,OAAO,CAAC;QACX,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,IAAI,CAAC,EAAE,IAAI,CAAC;KACb,CAAC,CAAC;IACH;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAYD,qBAAa,cAAe,YAAW,UAAU;IAC/C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAa;IAClC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAiB;IACzC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAqC;IACnE,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAS;IAC9C,OAAO,CAAC,WAAW,CAAuB;IAC1C,OAAO,CAAC,oBAAoB,CAAuB;IACnD,OAAO,CAAC,YAAY,CAA+C;IACnE,OAAO,CAAC,QAAQ,CAAC,uBAAuB,CAAgC;gBAE5D,OAAO,EAAE,iBAAiB;IActC;;OAEG;IACH,OAAO,IAAI,IAAI;IAOT,cAAc,CAClB,QAAQ,EAAE,cAAc,EACxB,OAAO,CAAC,EAAE,kBAAkB,GAAG;QAAE,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,GACrD,OAAO,CAAC,UAAU,CAAC;IAmEhB,iBAAiB,CACrB,QAAQ,EAAE,cAAc,EACxB,OAAO,CAAC,EAAE,kBAAkB,GAAG;QAAE,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,GACrD,OAAO,CAAC,IAAI,CAAC;IA6BV,cAAc,IAAI,OAAO,CAAC,UAAU,CAAC;IA+G3C,iBAAiB,IAAI,OAAO;IAK5B,qBAAqB,IAAI,cAAc,EAAE;YAI3B,aAAa;IAM3B,OAAO,CAAC,qBAAqB;IA+B7B,OAAO,CAAC,mBAAmB;IAI3B,OAAO,CAAC,gBAAgB;IASxB,OAAO,CAAC,wBAAwB;YAelB,kBAAkB;IAoHhC,OAAO,CAAC,YAAY;YAaN,gBAAgB;IAO9B,OAAO,CAAC,cAAc;CAQvB"}
1
+ {"version":3,"file":"social.d.ts","sourceRoot":"","sources":["../../src/lib/direct-auth/social.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAGL,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,KAAK,UAAU,EACf,KAAK,cAAc,EACnB,KAAK,kBAAkB,EACvB,KAAK,UAAU,EACf,KAAK,OAAO,EACZ,KAAK,IAAI,EACV,MAAM,eAAe,CAAC;AAwGvB,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,cAAc,CAAC;IACvB,OAAO,EAAE,cAAc,CAAC;IACxB,aAAa,EAAE,CACb,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,MAAM,EACpB,UAAU,CAAC,EAAE,MAAM,KAChB,OAAO,CAAC;QACX,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,IAAI,CAAC,EAAE,IAAI,CAAC;KACb,CAAC,CAAC;IACH;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAYD,qBAAa,cAAe,YAAW,UAAU;IAC/C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAa;IAClC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAiB;IACzC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAqC;IACnE,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAS;IAC9C,OAAO,CAAC,WAAW,CAAuB;IAC1C,OAAO,CAAC,oBAAoB,CAAuB;IACnD,OAAO,CAAC,YAAY,CAA+C;IACnE,OAAO,CAAC,QAAQ,CAAC,uBAAuB,CAAgC;gBAE5D,OAAO,EAAE,iBAAiB;IActC;;OAEG;IACH,OAAO,IAAI,IAAI;IAOT,cAAc,CAClB,QAAQ,EAAE,cAAc,EACxB,OAAO,CAAC,EAAE,kBAAkB,GAAG;QAAE,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,GACrD,OAAO,CAAC,UAAU,CAAC;IAmEhB,iBAAiB,CACrB,QAAQ,EAAE,cAAc,EACxB,OAAO,CAAC,EAAE,kBAAkB,GAAG;QAAE,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,GACrD,OAAO,CAAC,IAAI,CAAC;IA6BV,cAAc,IAAI,OAAO,CAAC,UAAU,CAAC;IA6H3C,iBAAiB,IAAI,OAAO;IAK5B,qBAAqB,IAAI,cAAc,EAAE;YAI3B,aAAa;IAM3B,OAAO,CAAC,qBAAqB;IA+B7B,OAAO,CAAC,mBAAmB;IAI3B,OAAO,CAAC,gBAAgB;IASxB,OAAO,CAAC,wBAAwB;YAelB,kBAAkB;IAmIhC,OAAO,CAAC,YAAY;YAaN,gBAAgB;IAO9B,OAAO,CAAC,cAAc;CAQvB"}
@@ -264,8 +264,21 @@ export class SocialAuthImpl {
264
264
  },
265
265
  };
266
266
  }
267
+ const providerId = await this.storage.get(STORAGE_KEYS.PROVIDER);
268
+ if (!providerId) {
269
+ await this.clearStoredState();
270
+ return {
271
+ success: false,
272
+ error: {
273
+ error: 'invalid_state',
274
+ error_description: 'No provider found. Please try again.',
275
+ code: 'AR004006',
276
+ meta: { retryable: false, severity: 'error' },
277
+ },
278
+ };
279
+ }
267
280
  try {
268
- const { session, user } = await this.exchangeToken(code, codeVerifier);
281
+ const { session, user } = await this.exchangeToken(code, codeVerifier, providerId);
269
282
  // Extract redirectTo from state (after validation)
270
283
  const stateData = storedState ? decodeStateData(storedState) : null;
271
284
  const redirectTo = stateData?.redirectTo && isValidRelativePath(stateData.redirectTo)
@@ -428,8 +441,22 @@ export class SocialAuthImpl {
428
441
  await this.clearStoredState();
429
442
  return;
430
443
  }
444
+ const providerId = await this.storage.get(STORAGE_KEYS.PROVIDER);
445
+ if (!providerId) {
446
+ resolve({
447
+ success: false,
448
+ error: {
449
+ error: 'invalid_state',
450
+ error_description: 'No provider found',
451
+ code: 'AR004006',
452
+ meta: { retryable: false, severity: 'error' },
453
+ },
454
+ });
455
+ await this.clearStoredState();
456
+ return;
457
+ }
431
458
  try {
432
- const { session, user } = await this.exchangeToken(data.code, codeVerifier);
459
+ const { session, user } = await this.exchangeToken(data.code, codeVerifier, providerId);
433
460
  // Extract redirectTo from state (after validation)
434
461
  const stateData = storedState ? decodeStateData(storedState) : null;
435
462
  const redirectTo = stateData?.redirectTo && isValidRelativePath(stateData.redirectTo)
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Smart Handoff SSO Handler for SvelteKit
3
+ *
4
+ * Handles handoff token verification and session management for cross-domain SSO
5
+ * in SvelteKit server-side code.
6
+ */
7
+ import type { Handle, RequestEvent } from '@sveltejs/kit';
8
+ import type { Session, User } from '@authrim/core';
9
+ import { type ServerSessionManagerOptions } from './session.js';
10
+ /**
11
+ * Handoff verification options
12
+ */
13
+ export interface HandoffVerifyOptions {
14
+ /**
15
+ * Authrim IdP URL (required if not using createAuthHandle)
16
+ */
17
+ issuer?: string;
18
+ /**
19
+ * OAuth client ID (required if not using createAuthHandle)
20
+ */
21
+ clientId?: string;
22
+ /**
23
+ * Handoff verify endpoint
24
+ * @default '/auth/external/handoff/verify'
25
+ */
26
+ verifyEndpoint?: string;
27
+ /**
28
+ * Error redirect path
29
+ * @default '/login'
30
+ */
31
+ errorRedirect?: string;
32
+ /**
33
+ * Session manager options
34
+ */
35
+ sessionOptions?: ServerSessionManagerOptions;
36
+ }
37
+ /**
38
+ * Verify handoff token from callback URL
39
+ *
40
+ * Usage in +page.server.ts:
41
+ * ```typescript
42
+ * export const load = async (event) => {
43
+ * const result = await verifyHandoffToken(event);
44
+ * if (!result.success) {
45
+ * throw redirect(302, '/login');
46
+ * }
47
+ * return { session: result.session, user: result.user };
48
+ * };
49
+ * ```
50
+ */
51
+ export declare function verifyHandoffToken(event: RequestEvent, options?: HandoffVerifyOptions): Promise<{
52
+ success: true;
53
+ session: Session;
54
+ user: User;
55
+ } | {
56
+ success: false;
57
+ error: string;
58
+ }>;
59
+ /**
60
+ * Create handoff handler for SvelteKit hooks
61
+ *
62
+ * Usage in hooks.server.ts:
63
+ * ```typescript
64
+ * import { sequence } from '@sveltejs/kit/hooks';
65
+ * import { createAuthHandle, createHandoffHandler } from '@authrim/sveltekit/server';
66
+ *
67
+ * export const handle = sequence(
68
+ * createAuthHandle({
69
+ * issuer: env.AUTHRIM_ISSUER,
70
+ * clientId: env.AUTHRIM_CLIENT_ID,
71
+ * }),
72
+ * createHandoffHandler()
73
+ * );
74
+ * ```
75
+ */
76
+ export declare function createHandoffHandler(options?: HandoffVerifyOptions): Handle;
77
+ //# sourceMappingURL=handoff.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handoff.d.ts","sourceRoot":"","sources":["../../src/lib/server/handoff.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAE1D,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,EAGL,KAAK,2BAA2B,EACjC,MAAM,cAAc,CAAC;AAEtB;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB;;OAEG;IACH,cAAc,CAAC,EAAE,2BAA2B,CAAC;CAC9C;AAmDD;;;;;;;;;;;;;GAaG;AACH,wBAAsB,kBAAkB,CACtC,KAAK,EAAE,YAAY,EACnB,OAAO,CAAC,EAAE,oBAAoB,GAC7B,OAAO,CACN;IAAE,OAAO,EAAE,IAAI,CAAC;IAAC,OAAO,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,IAAI,CAAA;CAAE,GAC/C;IAAE,OAAO,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CACpC,CA+DA;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,CAAC,EAAE,oBAAoB,GAAG,MAAM,CAwB3E"}
@@ -0,0 +1,133 @@
1
+ /**
2
+ * Smart Handoff SSO Handler for SvelteKit
3
+ *
4
+ * Handles handoff token verification and session management for cross-domain SSO
5
+ * in SvelteKit server-side code.
6
+ */
7
+ import { redirect } from '@sveltejs/kit';
8
+ import { createServerSessionManager, } from './session.js';
9
+ /**
10
+ * Get auth config from options or event.locals
11
+ */
12
+ function getAuthConfig(event, options) {
13
+ // Try to get from options first
14
+ if (options?.issuer && options?.clientId) {
15
+ return { issuer: options.issuer, clientId: options.clientId };
16
+ }
17
+ // Fallback to event.locals (set by createAuthHandle)
18
+ const issuer = event.locals.authrim_issuer;
19
+ const clientId = event.locals.authrim_client_id;
20
+ if (!issuer || !clientId) {
21
+ throw new Error('Authrim config not found. Please provide issuer and clientId in options, or use createAuthHandle.');
22
+ }
23
+ return { issuer, clientId };
24
+ }
25
+ /**
26
+ * Verify handoff token from callback URL
27
+ *
28
+ * Usage in +page.server.ts:
29
+ * ```typescript
30
+ * export const load = async (event) => {
31
+ * const result = await verifyHandoffToken(event);
32
+ * if (!result.success) {
33
+ * throw redirect(302, '/login');
34
+ * }
35
+ * return { session: result.session, user: result.user };
36
+ * };
37
+ * ```
38
+ */
39
+ export async function verifyHandoffToken(event, options) {
40
+ const { url } = event;
41
+ const handoffToken = url.searchParams.get('handoff_token');
42
+ const state = url.searchParams.get('state');
43
+ if (!handoffToken || !state) {
44
+ return { success: false, error: 'Missing handoff token or state' };
45
+ }
46
+ try {
47
+ const { issuer, clientId } = getAuthConfig(event, options);
48
+ const verifyEndpoint = options?.verifyEndpoint || '/auth/external/handoff/verify';
49
+ const response = await fetch(`${issuer}${verifyEndpoint}`, {
50
+ method: 'POST',
51
+ headers: { 'Content-Type': 'application/json' },
52
+ body: JSON.stringify({
53
+ handoff_token: handoffToken,
54
+ state: state,
55
+ client_id: clientId,
56
+ }),
57
+ });
58
+ if (!response.ok) {
59
+ const error = await response.json().catch(() => ({}));
60
+ return {
61
+ success: false,
62
+ error: error.error_description || 'Handoff verification failed',
63
+ };
64
+ }
65
+ const data = await response.json();
66
+ // Save session to cookie
67
+ const sessionManager = createServerSessionManager(options?.sessionOptions);
68
+ const authContext = {
69
+ session: {
70
+ id: data.session.id,
71
+ userId: data.session.userId,
72
+ createdAt: data.session.createdAt,
73
+ expiresAt: data.session.expiresAt,
74
+ },
75
+ user: {
76
+ id: data.user.id,
77
+ email: data.user.email ?? undefined,
78
+ name: data.user.name ?? undefined,
79
+ emailVerified: data.user.emailVerified,
80
+ },
81
+ };
82
+ sessionManager.set(event, authContext);
83
+ return {
84
+ success: true,
85
+ session: authContext.session,
86
+ user: authContext.user,
87
+ };
88
+ }
89
+ catch (error) {
90
+ return {
91
+ success: false,
92
+ error: error instanceof Error ? error.message : 'Unknown error',
93
+ };
94
+ }
95
+ }
96
+ /**
97
+ * Create handoff handler for SvelteKit hooks
98
+ *
99
+ * Usage in hooks.server.ts:
100
+ * ```typescript
101
+ * import { sequence } from '@sveltejs/kit/hooks';
102
+ * import { createAuthHandle, createHandoffHandler } from '@authrim/sveltekit/server';
103
+ *
104
+ * export const handle = sequence(
105
+ * createAuthHandle({
106
+ * issuer: env.AUTHRIM_ISSUER,
107
+ * clientId: env.AUTHRIM_CLIENT_ID,
108
+ * }),
109
+ * createHandoffHandler()
110
+ * );
111
+ * ```
112
+ */
113
+ export function createHandoffHandler(options) {
114
+ return async ({ event, resolve }) => {
115
+ // Check if this is a handoff callback
116
+ const { url } = event;
117
+ if (url.searchParams.has('handoff_token')) {
118
+ const result = await verifyHandoffToken(event, options);
119
+ if (!result.success) {
120
+ const errorRedirect = options?.errorRedirect || '/login';
121
+ // Use 303 See Other (POST → GET redirect, safer than 302)
122
+ throw redirect(303, errorRedirect);
123
+ }
124
+ // Remove handoff token from URL
125
+ const cleanUrl = new URL(url);
126
+ cleanUrl.searchParams.delete('handoff_token');
127
+ cleanUrl.searchParams.delete('state');
128
+ // Use 303 See Other (認証後のリダイレクトに適切)
129
+ throw redirect(303, cleanUrl.toString());
130
+ }
131
+ return resolve(event);
132
+ };
133
+ }
@@ -1,4 +1,5 @@
1
1
  export { createServerSessionManager, type ServerSessionManager, type ServerSessionManagerOptions, type ServerAuthContext, } from './session.js';
2
2
  export { createAuthHandle, getServerSessionManager, getAuthFromEvent, type AuthHandleOptions, } from './handle.js';
3
3
  export { requireAuth, createAuthLoad, isAuthenticated, getUser, getSession, type AuthLoadOptions, } from './load.js';
4
+ export { verifyHandoffToken, createHandoffHandler, type HandoffVerifyOptions, } from './handoff.js';
4
5
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/lib/server/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,0BAA0B,EAC1B,KAAK,oBAAoB,EACzB,KAAK,2BAA2B,EAChC,KAAK,iBAAiB,GACvB,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,gBAAgB,EAChB,uBAAuB,EACvB,gBAAgB,EAChB,KAAK,iBAAiB,GACvB,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,WAAW,EACX,cAAc,EACd,eAAe,EACf,OAAO,EACP,UAAU,EACV,KAAK,eAAe,GACrB,MAAM,WAAW,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/lib/server/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,0BAA0B,EAC1B,KAAK,oBAAoB,EACzB,KAAK,2BAA2B,EAChC,KAAK,iBAAiB,GACvB,MAAM,cAAc,CAAC;AAEtB,OAAO,EACL,gBAAgB,EAChB,uBAAuB,EACvB,gBAAgB,EAChB,KAAK,iBAAiB,GACvB,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,WAAW,EACX,cAAc,EACd,eAAe,EACf,OAAO,EACP,UAAU,EACV,KAAK,eAAe,GACrB,MAAM,WAAW,CAAC;AAEnB,OAAO,EACL,kBAAkB,EAClB,oBAAoB,EACpB,KAAK,oBAAoB,GAC1B,MAAM,cAAc,CAAC"}
@@ -1,3 +1,4 @@
1
1
  export { createServerSessionManager, } from './session.js';
2
2
  export { createAuthHandle, getServerSessionManager, getAuthFromEvent, } from './handle.js';
3
3
  export { requireAuth, createAuthLoad, isAuthenticated, getUser, getSession, } from './load.js';
4
+ export { verifyHandoffToken, createHandoffHandler, } from './handoff.js';
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@authrim/sveltekit",
3
3
  "packageManager": "pnpm@9.15.0",
4
- "version": "0.1.2",
4
+ "version": "0.1.4",
5
5
  "description": "SvelteKit SDK for Authrim authentication",
6
6
  "type": "module",
7
7
  "svelte": "./dist/index.js",
@@ -84,12 +84,12 @@
84
84
  "url": "https://github.com/authrim/js-sveltekit/issues"
85
85
  },
86
86
  "peerDependencies": {
87
- "@authrim/core": ">=0.1.10",
87
+ "@authrim/core": ">=0.1.14",
88
88
  "svelte": "^4.0.0 || ^5.0.0",
89
89
  "@sveltejs/kit": "^2.0.0"
90
90
  },
91
91
  "devDependencies": {
92
- "@authrim/core": "^0.1.10",
92
+ "@authrim/core": "^0.1.14",
93
93
  "@sveltejs/adapter-auto": "^3.0.0",
94
94
  "@sveltejs/kit": "^2.0.0",
95
95
  "@sveltejs/package": "^2.0.0",