@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.
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +2 -2
- package/dist/direct-auth/session.d.ts +1 -1
- package/dist/direct-auth/session.d.ts.map +1 -1
- package/dist/direct-auth/session.js +4 -1
- package/dist/direct-auth/social.d.ts +1 -1
- package/dist/direct-auth/social.d.ts.map +1 -1
- package/dist/direct-auth/social.js +29 -2
- package/dist/server/handoff.d.ts +77 -0
- package/dist/server/handoff.d.ts.map +1 -0
- package/dist/server/handoff.js +133 -0
- package/dist/server/index.d.ts +1 -0
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +1 -0
- package/package.json +3 -3
package/dist/client.d.ts.map
CHANGED
|
@@ -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,
|
|
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,
|
|
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,
|
|
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
|
+
}
|
package/dist/server/index.d.ts
CHANGED
|
@@ -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"}
|
package/dist/server/index.js
CHANGED
|
@@ -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.
|
|
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.
|
|
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.
|
|
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",
|