@nauth-toolkit/social-apple 0.1.14 → 0.1.17
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/nestjs/apple-social-auth.module.d.ts +37 -0
- package/dist/nestjs/apple-social-auth.module.d.ts.map +1 -1
- package/dist/nestjs/apple-social-auth.module.js +48 -4
- package/dist/nestjs/apple-social-auth.module.js.map +1 -1
- package/dist/nestjs/index.d.ts +5 -0
- package/dist/nestjs/index.d.ts.map +1 -1
- package/dist/nestjs/index.js +6 -0
- package/dist/nestjs/index.js.map +1 -1
- package/dist/src/apple-oauth.client.d.ts +59 -0
- package/dist/src/apple-oauth.client.d.ts.map +1 -1
- package/dist/src/apple-oauth.client.js +63 -2
- package/dist/src/apple-oauth.client.js.map +1 -1
- package/dist/src/apple-social-auth.service.d.ts +57 -1
- package/dist/src/apple-social-auth.service.d.ts.map +1 -1
- package/dist/src/apple-social-auth.service.js +80 -3
- package/dist/src/apple-social-auth.service.js.map +1 -1
- package/dist/src/dto/social-login.dto.d.ts +219 -0
- package/dist/src/dto/social-login.dto.d.ts.map +1 -1
- package/dist/src/dto/social-login.dto.js +219 -0
- package/dist/src/dto/social-login.dto.js.map +1 -1
- package/dist/src/index.d.ts +6 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +6 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/token-verifier.service.d.ts +45 -0
- package/dist/src/token-verifier.service.d.ts.map +1 -1
- package/dist/src/token-verifier.service.js +41 -1
- package/dist/src/token-verifier.service.js.map +1 -1
- package/dist/src/verified-token-profile.interface.d.ts +19 -0
- package/dist/src/verified-token-profile.interface.d.ts.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
|
@@ -1,10 +1,47 @@
|
|
|
1
1
|
import { OnModuleInit } from '@nestjs/common';
|
|
2
2
|
import { AppleSocialAuthService } from '../src/apple-social-auth.service';
|
|
3
3
|
import { SocialProviderRegistry } from '@nauth-toolkit/core/internal';
|
|
4
|
+
/**
|
|
5
|
+
* Apple Social Authentication Module (NestJS Adapter)
|
|
6
|
+
*
|
|
7
|
+
* Provides Apple OAuth integration for nauth-toolkit in NestJS applications.
|
|
8
|
+
* Automatically registers itself with SocialAuthService when imported.
|
|
9
|
+
*
|
|
10
|
+
* **Usage:**
|
|
11
|
+
* ```typescript
|
|
12
|
+
* import { AuthModule } from '@nauth-toolkit/nestjs';
|
|
13
|
+
* import { AppleSocialAuthModule } from '@nauth-toolkit/social-apple/nestjs';
|
|
14
|
+
*
|
|
15
|
+
* @Module({
|
|
16
|
+
* imports: [
|
|
17
|
+
* AuthModule.forRoot(config),
|
|
18
|
+
* AppleSocialAuthModule, // 👈 Auto-registers with SocialAuthService
|
|
19
|
+
* ],
|
|
20
|
+
* })
|
|
21
|
+
* export class AppModule {}
|
|
22
|
+
*
|
|
23
|
+
* // Use via registry (recommended for dynamic access)
|
|
24
|
+
* constructor(private socialAuthService: SocialAuthService) {}
|
|
25
|
+
*
|
|
26
|
+
* @Get('social/apple')
|
|
27
|
+
* async getAppleAuthUrl() {
|
|
28
|
+
* const appleProvider = this.socialAuthService.getProvider('apple');
|
|
29
|
+
* const authUrl = await appleProvider.getAuthUrl();
|
|
30
|
+
* return { authUrl };
|
|
31
|
+
* }
|
|
32
|
+
*
|
|
33
|
+
* // Or inject directly
|
|
34
|
+
* constructor(private appleAuth: AppleSocialAuthService) {}
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
4
37
|
export declare class AppleSocialAuthModule implements OnModuleInit {
|
|
5
38
|
private readonly appleSocialAuthService;
|
|
6
39
|
private readonly providerRegistry;
|
|
7
40
|
constructor(appleSocialAuthService: AppleSocialAuthService, providerRegistry: SocialProviderRegistry);
|
|
41
|
+
/**
|
|
42
|
+
* Auto-register Apple provider with the SocialProviderRegistry
|
|
43
|
+
* when the module is initialized (only if enabled in config).
|
|
44
|
+
*/
|
|
8
45
|
onModuleInit(): void;
|
|
9
46
|
}
|
|
10
47
|
//# sourceMappingURL=apple-social-auth.module.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"apple-social-auth.module.d.ts","sourceRoot":"","sources":["../../nestjs/apple-social-auth.module.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,YAAY,EAAE,MAAM,gBAAgB,CAAC;AACtD,OAAO,EAAE,sBAAsB,EAAE,MAAM,kCAAkC,CAAC;AAY1E,OAAO,EAIL,sBAAsB,EAGvB,MAAM,8BAA8B,CAAC;
|
|
1
|
+
{"version":3,"file":"apple-social-auth.module.d.ts","sourceRoot":"","sources":["../../nestjs/apple-social-auth.module.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,YAAY,EAAE,MAAM,gBAAgB,CAAC;AACtD,OAAO,EAAE,sBAAsB,EAAE,MAAM,kCAAkC,CAAC;AAY1E,OAAO,EAIL,sBAAsB,EAGvB,MAAM,8BAA8B,CAAC;AAGtC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,qBAmEa,qBAAsB,YAAW,YAAY;IAEtD,OAAO,CAAC,QAAQ,CAAC,sBAAsB;IACvC,OAAO,CAAC,QAAQ,CAAC,gBAAgB;gBADhB,sBAAsB,EAAE,sBAAsB,EAC9C,gBAAgB,EAAE,sBAAsB;IAG3D;;;OAGG;IACH,YAAY,IAAI,IAAI;CAOrB"}
|
|
@@ -12,9 +12,44 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
12
12
|
exports.AppleSocialAuthModule = void 0;
|
|
13
13
|
const common_1 = require("@nestjs/common");
|
|
14
14
|
const apple_social_auth_service_1 = require("../src/apple-social-auth.service");
|
|
15
|
+
// Public API imports
|
|
15
16
|
const core_1 = require("@nauth-toolkit/core");
|
|
17
|
+
// Internal API imports (for provider implementations)
|
|
16
18
|
const internal_1 = require("@nauth-toolkit/core/internal");
|
|
17
19
|
const token_verifier_service_1 = require("../src/token-verifier.service");
|
|
20
|
+
/**
|
|
21
|
+
* Apple Social Authentication Module (NestJS Adapter)
|
|
22
|
+
*
|
|
23
|
+
* Provides Apple OAuth integration for nauth-toolkit in NestJS applications.
|
|
24
|
+
* Automatically registers itself with SocialAuthService when imported.
|
|
25
|
+
*
|
|
26
|
+
* **Usage:**
|
|
27
|
+
* ```typescript
|
|
28
|
+
* import { AuthModule } from '@nauth-toolkit/nestjs';
|
|
29
|
+
* import { AppleSocialAuthModule } from '@nauth-toolkit/social-apple/nestjs';
|
|
30
|
+
*
|
|
31
|
+
* @Module({
|
|
32
|
+
* imports: [
|
|
33
|
+
* AuthModule.forRoot(config),
|
|
34
|
+
* AppleSocialAuthModule, // 👈 Auto-registers with SocialAuthService
|
|
35
|
+
* ],
|
|
36
|
+
* })
|
|
37
|
+
* export class AppModule {}
|
|
38
|
+
*
|
|
39
|
+
* // Use via registry (recommended for dynamic access)
|
|
40
|
+
* constructor(private socialAuthService: SocialAuthService) {}
|
|
41
|
+
*
|
|
42
|
+
* @Get('social/apple')
|
|
43
|
+
* async getAppleAuthUrl() {
|
|
44
|
+
* const appleProvider = this.socialAuthService.getProvider('apple');
|
|
45
|
+
* const authUrl = await appleProvider.getAuthUrl();
|
|
46
|
+
* return { authUrl };
|
|
47
|
+
* }
|
|
48
|
+
*
|
|
49
|
+
* // Or inject directly
|
|
50
|
+
* constructor(private appleAuth: AppleSocialAuthService) {}
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
18
53
|
let AppleSocialAuthModule = class AppleSocialAuthModule {
|
|
19
54
|
appleSocialAuthService;
|
|
20
55
|
providerRegistry;
|
|
@@ -22,8 +57,12 @@ let AppleSocialAuthModule = class AppleSocialAuthModule {
|
|
|
22
57
|
this.appleSocialAuthService = appleSocialAuthService;
|
|
23
58
|
this.providerRegistry = providerRegistry;
|
|
24
59
|
}
|
|
60
|
+
/**
|
|
61
|
+
* Auto-register Apple provider with the SocialProviderRegistry
|
|
62
|
+
* when the module is initialized (only if enabled in config).
|
|
63
|
+
*/
|
|
25
64
|
onModuleInit() {
|
|
26
|
-
const config = this.appleSocialAuthService['config'];
|
|
65
|
+
const config = this.appleSocialAuthService['config']; // Access protected config
|
|
27
66
|
const providerConfig = config.social?.apple;
|
|
28
67
|
if (providerConfig?.enabled) {
|
|
29
68
|
this.providerRegistry.registerProvider(this.appleSocialAuthService);
|
|
@@ -33,7 +72,9 @@ let AppleSocialAuthModule = class AppleSocialAuthModule {
|
|
|
33
72
|
exports.AppleSocialAuthModule = AppleSocialAuthModule;
|
|
34
73
|
exports.AppleSocialAuthModule = AppleSocialAuthModule = __decorate([
|
|
35
74
|
(0, common_1.Module)({
|
|
75
|
+
// No imports needed - AuthModule is @Global() so its providers are available
|
|
36
76
|
providers: [
|
|
77
|
+
// Token verifier for Apple ID tokens
|
|
37
78
|
{
|
|
38
79
|
provide: 'APPLE_TOKEN_VERIFIER',
|
|
39
80
|
useFactory: (config) => {
|
|
@@ -41,9 +82,12 @@ exports.AppleSocialAuthModule = AppleSocialAuthModule = __decorate([
|
|
|
41
82
|
},
|
|
42
83
|
inject: ['NAUTH_CONFIG'],
|
|
43
84
|
},
|
|
85
|
+
// Apple Social Auth Service (factory provider)
|
|
44
86
|
{
|
|
45
87
|
provide: apple_social_auth_service_1.AppleSocialAuthService,
|
|
46
|
-
useFactory: (config, logger, authService, socialAuthService, jwtService, sessionService, challengeHelper, clientInfoService, stateStore, userRepository, phoneVerificationService, auditService,
|
|
88
|
+
useFactory: (config, logger, authService, socialAuthService, jwtService, sessionService, challengeHelper, clientInfoService, stateStore, userRepository, phoneVerificationService, auditService, // Optional - only available when auditLogs.enabled is true
|
|
89
|
+
trustedDeviceService, // Optional - only available when rememberDevices is enabled
|
|
90
|
+
tokenVerifier) => {
|
|
47
91
|
return new apple_social_auth_service_1.AppleSocialAuthService(config, logger, authService, socialAuthService, jwtService, sessionService, challengeHelper, clientInfoService, stateStore, userRepository, phoneVerificationService, auditService, trustedDeviceService, tokenVerifier);
|
|
48
92
|
},
|
|
49
93
|
inject: [
|
|
@@ -58,8 +102,8 @@ exports.AppleSocialAuthModule = AppleSocialAuthModule = __decorate([
|
|
|
58
102
|
'SOCIAL_AUTH_STATE_STORE',
|
|
59
103
|
'UserRepository',
|
|
60
104
|
{ token: core_1.PhoneVerificationService, optional: true },
|
|
61
|
-
{ token: internal_1.AuthAuditService, optional: true },
|
|
62
|
-
{ token: internal_1.TrustedDeviceService, optional: true },
|
|
105
|
+
{ token: internal_1.AuthAuditService, optional: true }, // Optional - only available when auditLogs.enabled is true
|
|
106
|
+
{ token: internal_1.TrustedDeviceService, optional: true }, // Optional - only available when rememberDevices is enabled
|
|
63
107
|
{ token: 'APPLE_TOKEN_VERIFIER', optional: true },
|
|
64
108
|
],
|
|
65
109
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"apple-social-auth.module.js","sourceRoot":"","sources":["../../nestjs/apple-social-auth.module.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,2CAAsD;AACtD,gFAA0E;
|
|
1
|
+
{"version":3,"file":"apple-social-auth.module.js","sourceRoot":"","sources":["../../nestjs/apple-social-auth.module.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,2CAAsD;AACtD,gFAA0E;AAC1E,qBAAqB;AACrB,8CAQ6B;AAC7B,sDAAsD;AACtD,2DAOsC;AACtC,0EAAkG;AAElG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAoEI,IAAM,qBAAqB,GAA3B,MAAM,qBAAqB;IAEb;IACA;IAFnB,YACmB,sBAA8C,EAC9C,gBAAwC;QADxC,2BAAsB,GAAtB,sBAAsB,CAAwB;QAC9C,qBAAgB,GAAhB,gBAAgB,CAAwB;IACxD,CAAC;IAEJ;;;OAGG;IACH,YAAY;QACV,MAAM,MAAM,GAAG,IAAI,CAAC,sBAAsB,CAAC,QAAQ,CAAgB,CAAC,CAAC,0BAA0B;QAC/F,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC;QAC5C,IAAI,cAAc,EAAE,OAAO,EAAE,CAAC;YAC5B,IAAI,CAAC,gBAAgB,CAAC,gBAAgB,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;QACtE,CAAC;IACH,CAAC;CACF,CAAA;AAjBY,sDAAqB;gCAArB,qBAAqB;IAnEjC,IAAA,eAAM,EAAC;QACN,6EAA6E;QAC7E,SAAS,EAAE;YACT,qCAAqC;YACrC;gBACE,OAAO,EAAE,sBAAsB;gBAC/B,UAAU,EAAE,CAAC,MAAmB,EAAE,EAAE;oBAClC,OAAO,IAAI,6CAAyB,CAAC,MAAM,CAAC,CAAC;gBAC/C,CAAC;gBACD,MAAM,EAAE,CAAC,cAAc,CAAC;aACzB;YACD,+CAA+C;YAC/C;gBACE,OAAO,EAAE,kDAAsB;gBAC/B,UAAU,EAAE,CACV,MAAmB,EACnB,MAAmB,EACnB,WAAwB,EACxB,iBAAoC,EACpC,UAAsB,EACtB,cAA8B,EAC9B,eAA2C,EAC3C,iBAAoC,EACpC,UAAgE,EAChE,cAAmB,EACnB,wBAAmD,EACnD,YAAuC,EAAE,2DAA2D;gBACpG,oBAA2C,EAAE,4DAA4D;gBACzG,aAAqC,EACrC,EAAE;oBACF,OAAO,IAAI,kDAAsB,CAC/B,MAAM,EACN,MAAM,EACN,WAAW,EACX,iBAAiB,EACjB,UAAU,EACV,cAAc,EACd,eAAe,EACf,iBAAiB,EACjB,UAAU,EACV,cAAc,EACd,wBAAwB,EACxB,YAAY,EACZ,oBAAoB,EACpB,aAAa,CACd,CAAC;gBACJ,CAAC;gBACD,MAAM,EAAE;oBACN,cAAc;oBACd,cAAc;oBACd,kBAAW;oBACX,wBAAiB;oBACjB,qBAAU;oBACV,yBAAc;oBACd,qCAA0B;oBAC1B,wBAAiB;oBACjB,yBAAyB;oBACzB,gBAAgB;oBAChB,EAAE,KAAK,EAAE,+BAAwB,EAAE,QAAQ,EAAE,IAAI,EAAE;oBACnD,EAAE,KAAK,EAAE,2BAAwB,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,2DAA2D;oBAChH,EAAE,KAAK,EAAE,+BAAoB,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,4DAA4D;oBAC7G,EAAE,KAAK,EAAE,sBAAsB,EAAE,QAAQ,EAAE,IAAI,EAAE;iBAClD;aACF;SACF;QACD,OAAO,EAAE,CAAC,kDAAsB,CAAC;KAClC,CAAC;qCAG2C,kDAAsB;QAC5B,iCAAsB;GAHhD,qBAAqB,CAiBjC"}
|
package/dist/nestjs/index.d.ts
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @nauth-toolkit/social-apple/nestjs
|
|
3
|
+
*
|
|
4
|
+
* NestJS adapter for Apple Social Authentication
|
|
5
|
+
*/
|
|
1
6
|
export { AppleSocialAuthModule } from './apple-social-auth.module';
|
|
2
7
|
export * from '../src/apple-social-auth.service';
|
|
3
8
|
export * from '../src/apple-oauth.client';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../nestjs/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../nestjs/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AAGnE,cAAc,kCAAkC,CAAC;AACjD,cAAc,2BAA2B,CAAC;AAC1C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,yCAAyC,CAAC;AACxD,cAAc,6BAA6B,CAAC"}
|
package/dist/nestjs/index.js
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @nauth-toolkit/social-apple/nestjs
|
|
4
|
+
*
|
|
5
|
+
* NestJS adapter for Apple Social Authentication
|
|
6
|
+
*/
|
|
2
7
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
8
|
if (k2 === undefined) k2 = k;
|
|
4
9
|
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
@@ -17,6 +22,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
17
22
|
exports.AppleSocialAuthModule = void 0;
|
|
18
23
|
var apple_social_auth_module_1 = require("./apple-social-auth.module");
|
|
19
24
|
Object.defineProperty(exports, "AppleSocialAuthModule", { enumerable: true, get: function () { return apple_social_auth_module_1.AppleSocialAuthModule; } });
|
|
25
|
+
// Re-export core Apple social auth components
|
|
20
26
|
__exportStar(require("../src/apple-social-auth.service"), exports);
|
|
21
27
|
__exportStar(require("../src/apple-oauth.client"), exports);
|
|
22
28
|
__exportStar(require("../src/token-verifier.service"), exports);
|
package/dist/nestjs/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../nestjs/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../nestjs/index.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;;;;;;;;;;;;;;;;AAEH,uEAAmE;AAA1D,iIAAA,qBAAqB,OAAA;AAE9B,8CAA8C;AAC9C,mEAAiD;AACjD,4DAA0C;AAC1C,gEAA8C;AAC9C,0EAAwD;AACxD,8DAA4C"}
|
|
@@ -1,15 +1,74 @@
|
|
|
1
1
|
import { OAuthClient, OAuthConfig, OAuthUserProfile } from '@nauth-toolkit/core';
|
|
2
|
+
/**
|
|
3
|
+
* Apple OAuth Client Implementation (Platform-Agnostic)
|
|
4
|
+
*
|
|
5
|
+
* Handles OAuth flow with Apple's Sign in with Apple API
|
|
6
|
+
* Uses Apple's userinfo endpoint for profile data
|
|
7
|
+
*
|
|
8
|
+
* This is a plain TypeScript class with no framework dependencies.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```typescript
|
|
12
|
+
* const client = new AppleOAuthClient({
|
|
13
|
+
* clientId: 'apple_client_id',
|
|
14
|
+
* clientSecret: 'apple_client_secret',
|
|
15
|
+
* redirectUri: 'https://myapp.com/auth/apple/callback'
|
|
16
|
+
* });
|
|
17
|
+
*
|
|
18
|
+
* const profile = await client.getUserProfile(accessToken);
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
2
21
|
export declare class AppleOAuthClient implements OAuthClient {
|
|
3
22
|
private readonly config;
|
|
4
23
|
private readonly tokenEndpoint;
|
|
5
24
|
private readonly userInfoEndpoint;
|
|
6
25
|
constructor(config: OAuthConfig);
|
|
26
|
+
/**
|
|
27
|
+
* Exchange authorization code for access token
|
|
28
|
+
*
|
|
29
|
+
* @param code - Authorization code from Apple OAuth callback
|
|
30
|
+
* @param redirectUri - Redirect URI used in OAuth flow
|
|
31
|
+
* @returns Access token and optional refresh token
|
|
32
|
+
* @throws {Error} When token exchange fails
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* ```typescript
|
|
36
|
+
* const tokens = await client.exchangeCodeForToken(code, redirectUri);
|
|
37
|
+
* console.log(tokens.accessToken); // access_token_here
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
7
40
|
exchangeCodeForToken(code: string, redirectUri: string): Promise<{
|
|
8
41
|
accessToken: string;
|
|
9
42
|
refreshToken?: string;
|
|
10
43
|
expiresIn?: number;
|
|
11
44
|
}>;
|
|
45
|
+
/**
|
|
46
|
+
* Get user profile from Apple using access token
|
|
47
|
+
*
|
|
48
|
+
* @param accessToken - OAuth access token
|
|
49
|
+
* @returns User profile data
|
|
50
|
+
* @throws {Error} When API call fails or token is invalid
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* ```typescript
|
|
54
|
+
* const profile = await client.getUserProfile(accessToken);
|
|
55
|
+
* console.log(profile.email); // user@icloud.com
|
|
56
|
+
* console.log(profile.firstName); // John
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
12
59
|
getUserProfile(accessToken: string): Promise<OAuthUserProfile>;
|
|
60
|
+
/**
|
|
61
|
+
* Generate Apple OAuth authorization URL
|
|
62
|
+
*
|
|
63
|
+
* @param state - Optional state parameter for CSRF protection
|
|
64
|
+
* @returns Authorization URL for redirecting user to Apple
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* ```typescript
|
|
68
|
+
* const authUrl = client.getAuthorizationUrl('random-state');
|
|
69
|
+
* // Redirect user to authUrl
|
|
70
|
+
* ```
|
|
71
|
+
*/
|
|
13
72
|
getAuthorizationUrl(state?: string): string;
|
|
14
73
|
}
|
|
15
74
|
//# sourceMappingURL=apple-oauth.client.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"apple-oauth.client.d.ts","sourceRoot":"","sources":["../../src/apple-oauth.client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,gBAAgB,EAAiC,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"apple-oauth.client.d.ts","sourceRoot":"","sources":["../../src/apple-oauth.client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,gBAAgB,EAAiC,MAAM,qBAAqB,CAAC;AAEhH;;;;;;;;;;;;;;;;;;GAkBG;AACH,qBAAa,gBAAiB,YAAW,WAAW;IAClD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAc;IACrC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAA0C;IACxE,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAA6C;gBAElE,MAAM,EAAE,WAAW;IAO/B;;;;;;;;;;;;;OAaG;IACG,oBAAoB,CACxB,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC;QACT,WAAW,EAAE,MAAM,CAAC;QACpB,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC;IAyCF;;;;;;;;;;;;;OAaG;IACG,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;IA0CpE;;;;;;;;;;;OAWG;IACH,mBAAmB,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM;CAe5C"}
|
|
@@ -2,6 +2,25 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.AppleOAuthClient = void 0;
|
|
4
4
|
const core_1 = require("@nauth-toolkit/core");
|
|
5
|
+
/**
|
|
6
|
+
* Apple OAuth Client Implementation (Platform-Agnostic)
|
|
7
|
+
*
|
|
8
|
+
* Handles OAuth flow with Apple's Sign in with Apple API
|
|
9
|
+
* Uses Apple's userinfo endpoint for profile data
|
|
10
|
+
*
|
|
11
|
+
* This is a plain TypeScript class with no framework dependencies.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```typescript
|
|
15
|
+
* const client = new AppleOAuthClient({
|
|
16
|
+
* clientId: 'apple_client_id',
|
|
17
|
+
* clientSecret: 'apple_client_secret',
|
|
18
|
+
* redirectUri: 'https://myapp.com/auth/apple/callback'
|
|
19
|
+
* });
|
|
20
|
+
*
|
|
21
|
+
* const profile = await client.getUserProfile(accessToken);
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
5
24
|
class AppleOAuthClient {
|
|
6
25
|
config;
|
|
7
26
|
tokenEndpoint = 'https://appleid.apple.com/auth/token';
|
|
@@ -12,6 +31,20 @@ class AppleOAuthClient {
|
|
|
12
31
|
...config,
|
|
13
32
|
};
|
|
14
33
|
}
|
|
34
|
+
/**
|
|
35
|
+
* Exchange authorization code for access token
|
|
36
|
+
*
|
|
37
|
+
* @param code - Authorization code from Apple OAuth callback
|
|
38
|
+
* @param redirectUri - Redirect URI used in OAuth flow
|
|
39
|
+
* @returns Access token and optional refresh token
|
|
40
|
+
* @throws {Error} When token exchange fails
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* ```typescript
|
|
44
|
+
* const tokens = await client.exchangeCodeForToken(code, redirectUri);
|
|
45
|
+
* console.log(tokens.accessToken); // access_token_here
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
15
48
|
async exchangeCodeForToken(code, redirectUri) {
|
|
16
49
|
const params = new URLSearchParams({
|
|
17
50
|
client_id: this.config.clientId,
|
|
@@ -46,6 +79,20 @@ class AppleOAuthClient {
|
|
|
46
79
|
throw new core_1.NAuthException(core_1.AuthErrorCode.SOCIAL_TOKEN_INVALID, 'Apple token exchange failed: Unknown error');
|
|
47
80
|
}
|
|
48
81
|
}
|
|
82
|
+
/**
|
|
83
|
+
* Get user profile from Apple using access token
|
|
84
|
+
*
|
|
85
|
+
* @param accessToken - OAuth access token
|
|
86
|
+
* @returns User profile data
|
|
87
|
+
* @throws {Error} When API call fails or token is invalid
|
|
88
|
+
*
|
|
89
|
+
* @example
|
|
90
|
+
* ```typescript
|
|
91
|
+
* const profile = await client.getUserProfile(accessToken);
|
|
92
|
+
* console.log(profile.email); // user@icloud.com
|
|
93
|
+
* console.log(profile.firstName); // John
|
|
94
|
+
* ```
|
|
95
|
+
*/
|
|
49
96
|
async getUserProfile(accessToken) {
|
|
50
97
|
try {
|
|
51
98
|
const response = await fetch(this.userInfoEndpoint, {
|
|
@@ -60,14 +107,16 @@ class AppleOAuthClient {
|
|
|
60
107
|
throw new core_1.NAuthException(core_1.AuthErrorCode.INTERNAL_ERROR, `Apple API call failed: ${response.status} ${response.statusText}`);
|
|
61
108
|
}
|
|
62
109
|
const data = (await response.json());
|
|
110
|
+
// Map Apple's response to our standardized format
|
|
111
|
+
// Apple provides name in a nested object format
|
|
63
112
|
const firstName = data.name?.firstName || null;
|
|
64
113
|
const lastName = data.name?.lastName || null;
|
|
65
114
|
return {
|
|
66
|
-
id: data.sub,
|
|
115
|
+
id: data.sub, // Apple uses 'sub' as the user identifier
|
|
67
116
|
email: data.email || null,
|
|
68
117
|
firstName,
|
|
69
118
|
lastName,
|
|
70
|
-
picture: null,
|
|
119
|
+
picture: null, // Apple doesn't provide profile pictures
|
|
71
120
|
verified: data.email_verified || false,
|
|
72
121
|
raw: data,
|
|
73
122
|
};
|
|
@@ -79,6 +128,18 @@ class AppleOAuthClient {
|
|
|
79
128
|
throw new core_1.NAuthException(core_1.AuthErrorCode.INTERNAL_ERROR, 'Apple profile fetch failed: Unknown error');
|
|
80
129
|
}
|
|
81
130
|
}
|
|
131
|
+
/**
|
|
132
|
+
* Generate Apple OAuth authorization URL
|
|
133
|
+
*
|
|
134
|
+
* @param state - Optional state parameter for CSRF protection
|
|
135
|
+
* @returns Authorization URL for redirecting user to Apple
|
|
136
|
+
*
|
|
137
|
+
* @example
|
|
138
|
+
* ```typescript
|
|
139
|
+
* const authUrl = client.getAuthorizationUrl('random-state');
|
|
140
|
+
* // Redirect user to authUrl
|
|
141
|
+
* ```
|
|
142
|
+
*/
|
|
82
143
|
getAuthorizationUrl(state) {
|
|
83
144
|
const params = new URLSearchParams({
|
|
84
145
|
client_id: this.config.clientId,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"apple-oauth.client.js","sourceRoot":"","sources":["../../src/apple-oauth.client.ts"],"names":[],"mappings":";;;AAAA,8CAAgH;
|
|
1
|
+
{"version":3,"file":"apple-oauth.client.js","sourceRoot":"","sources":["../../src/apple-oauth.client.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,37 @@
|
|
|
1
1
|
import { AuthService, SocialAuthService, ClientInfoService, NAuthConfig, NAuthLogger, OAuthUserProfile, PhoneVerificationService, ISocialAuthProviderService, ITokenVerifierService, BaseUser } from '@nauth-toolkit/core';
|
|
2
|
-
import { BaseSocialAuthProviderService, JwtService, SessionService, AuthChallengeHelperService, AuthAuditService,
|
|
2
|
+
import { BaseSocialAuthProviderService, JwtService, SessionService, AuthChallengeHelperService, AuthAuditService, // Internal version with recordEvent()
|
|
3
|
+
TrustedDeviceService } from '@nauth-toolkit/core/internal';
|
|
3
4
|
import { Repository } from 'typeorm';
|
|
5
|
+
/**
|
|
6
|
+
* Apple Social Authentication Service (Platform-Agnostic)
|
|
7
|
+
*
|
|
8
|
+
* Handles Apple OAuth flow including:
|
|
9
|
+
* - OAuth web flow (redirect-based)
|
|
10
|
+
* - Native mobile token verification
|
|
11
|
+
* - Account linking
|
|
12
|
+
*
|
|
13
|
+
* This is a plain TypeScript class with no framework dependencies.
|
|
14
|
+
* Use `@nauth-toolkit/social-apple/nestjs` for NestJS integration.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```typescript
|
|
18
|
+
* // Direct instantiation (platform-agnostic)
|
|
19
|
+
* const appleAuth = new AppleSocialAuthService(
|
|
20
|
+
* config,
|
|
21
|
+
* logger,
|
|
22
|
+
* authService,
|
|
23
|
+
* socialAuthService,
|
|
24
|
+
* jwtService,
|
|
25
|
+
* sessionService,
|
|
26
|
+
* challengeHelper,
|
|
27
|
+
* clientInfoService,
|
|
28
|
+
* auditService,
|
|
29
|
+
* stateStore,
|
|
30
|
+
* phoneVerificationService,
|
|
31
|
+
* tokenVerifier
|
|
32
|
+
* );
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
4
35
|
export declare class AppleSocialAuthService extends BaseSocialAuthProviderService implements ISocialAuthProviderService {
|
|
5
36
|
readonly providerName = "apple";
|
|
6
37
|
private readonly oauthClient;
|
|
@@ -9,8 +40,33 @@ export declare class AppleSocialAuthService extends BaseSocialAuthProviderServic
|
|
|
9
40
|
timestamp: number;
|
|
10
41
|
provider: string;
|
|
11
42
|
}>, userRepository: Repository<BaseUser>, phoneVerificationService?: PhoneVerificationService, auditService?: AuthAuditService, trustedDeviceService?: TrustedDeviceService, tokenVerifier?: ITokenVerifierService);
|
|
43
|
+
/**
|
|
44
|
+
* Generate OAuth authorization URL for Apple
|
|
45
|
+
*
|
|
46
|
+
* @param state - Optional state parameter for CSRF protection
|
|
47
|
+
* @returns Authorization URL for redirecting user to Apple
|
|
48
|
+
*/
|
|
12
49
|
getAuthUrl(state?: string): Promise<string>;
|
|
50
|
+
/**
|
|
51
|
+
* Get OAuth user profile from callback
|
|
52
|
+
*
|
|
53
|
+
* Exchanges authorization code for access token and fetches user profile.
|
|
54
|
+
*
|
|
55
|
+
* @param code - Authorization code from Apple OAuth callback
|
|
56
|
+
* @param _state - State parameter (validated by base class)
|
|
57
|
+
* @returns User profile from Apple
|
|
58
|
+
* @protected
|
|
59
|
+
*/
|
|
13
60
|
protected getOAuthProfile(code: string, _state: string): Promise<OAuthUserProfile>;
|
|
61
|
+
/**
|
|
62
|
+
* Verify Apple ID token from native mobile apps
|
|
63
|
+
*
|
|
64
|
+
* @param idToken - Apple ID token from native Sign in with Apple
|
|
65
|
+
* @param _accessToken - Access token (not used for Apple)
|
|
66
|
+
* @param profileData - Optional profile data (name fields from first sign-in)
|
|
67
|
+
* @returns User profile from verified token
|
|
68
|
+
* @protected
|
|
69
|
+
*/
|
|
14
70
|
protected verifyNativeToken(idToken: string, _accessToken?: string, profileData?: unknown): Promise<OAuthUserProfile>;
|
|
15
71
|
}
|
|
16
72
|
//# sourceMappingURL=apple-social-auth.service.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"apple-social-auth.service.d.ts","sourceRoot":"","sources":["../../src/apple-social-auth.service.ts"],"names":[],"mappings":"AACA,OAAO,EACL,WAAW,EACX,iBAAiB,EACjB,iBAAiB,EACjB,WAAW,EACX,WAAW,EACX,gBAAgB,EAGhB,wBAAwB,EACxB,0BAA0B,EAC1B,qBAAqB,EACrB,QAAQ,EACT,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,6BAA6B,EAC7B,UAAU,EACV,cAAc,EACd,0BAA0B,EAC1B,gBAAgB,
|
|
1
|
+
{"version":3,"file":"apple-social-auth.service.d.ts","sourceRoot":"","sources":["../../src/apple-social-auth.service.ts"],"names":[],"mappings":"AACA,OAAO,EACL,WAAW,EACX,iBAAiB,EACjB,iBAAiB,EACjB,WAAW,EACX,WAAW,EACX,gBAAgB,EAGhB,wBAAwB,EACxB,0BAA0B,EAC1B,qBAAqB,EACrB,QAAQ,EACT,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,6BAA6B,EAC7B,UAAU,EACV,cAAc,EACd,0BAA0B,EAC1B,gBAAgB,EAAE,sCAAsC;AACxD,oBAAoB,EACrB,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAKrC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,qBAAa,sBAAuB,SAAQ,6BAA8B,YAAW,0BAA0B;IAC7G,QAAQ,CAAC,YAAY,WAAW;IAChC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAA0B;IACtD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAA+B;gBAG3D,MAAM,EAAE,WAAW,EACnB,MAAM,EAAE,WAAW,EACnB,WAAW,EAAE,WAAW,EACxB,iBAAiB,EAAE,iBAAiB,EACpC,UAAU,EAAE,UAAU,EACtB,cAAc,EAAE,cAAc,EAC9B,eAAe,EAAE,0BAA0B,EAC3C,iBAAiB,EAAE,iBAAiB,EAEpC,UAAU,EAAE,GAAG,CAAC,MAAM,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,EAChE,cAAc,EAAE,UAAU,CAAC,QAAQ,CAAC,EAEpC,wBAAwB,CAAC,EAAE,wBAAwB,EAEnD,YAAY,CAAC,EAAE,gBAAgB,EAE/B,oBAAoB,CAAC,EAAE,oBAAoB,EAE3C,aAAa,CAAC,EAAE,qBAAqB;IAqDvC;;;;;OAKG;IACG,UAAU,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAQjD;;;;;;;;;OASG;cACa,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAgBxF;;;;;;;;OAQG;cACa,iBAAiB,CAC/B,OAAO,EAAE,MAAM,EACf,YAAY,CAAC,EAAE,MAAM,EACrB,WAAW,CAAC,EAAE,OAAO,GACpB,OAAO,CAAC,gBAAgB,CAAC;CAwC7B"}
|
|
@@ -1,34 +1,81 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.AppleSocialAuthService = void 0;
|
|
4
|
+
// Public API imports
|
|
4
5
|
const core_1 = require("@nauth-toolkit/core");
|
|
6
|
+
// Internal API imports (for provider implementations)
|
|
5
7
|
const internal_1 = require("@nauth-toolkit/core/internal");
|
|
6
8
|
const apple_oauth_client_1 = require("./apple-oauth.client");
|
|
7
9
|
const token_verifier_service_1 = require("./token-verifier.service");
|
|
10
|
+
/**
|
|
11
|
+
* Apple Social Authentication Service (Platform-Agnostic)
|
|
12
|
+
*
|
|
13
|
+
* Handles Apple OAuth flow including:
|
|
14
|
+
* - OAuth web flow (redirect-based)
|
|
15
|
+
* - Native mobile token verification
|
|
16
|
+
* - Account linking
|
|
17
|
+
*
|
|
18
|
+
* This is a plain TypeScript class with no framework dependencies.
|
|
19
|
+
* Use `@nauth-toolkit/social-apple/nestjs` for NestJS integration.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```typescript
|
|
23
|
+
* // Direct instantiation (platform-agnostic)
|
|
24
|
+
* const appleAuth = new AppleSocialAuthService(
|
|
25
|
+
* config,
|
|
26
|
+
* logger,
|
|
27
|
+
* authService,
|
|
28
|
+
* socialAuthService,
|
|
29
|
+
* jwtService,
|
|
30
|
+
* sessionService,
|
|
31
|
+
* challengeHelper,
|
|
32
|
+
* clientInfoService,
|
|
33
|
+
* auditService,
|
|
34
|
+
* stateStore,
|
|
35
|
+
* phoneVerificationService,
|
|
36
|
+
* tokenVerifier
|
|
37
|
+
* );
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
8
40
|
class AppleSocialAuthService extends internal_1.BaseSocialAuthProviderService {
|
|
9
41
|
providerName = 'apple';
|
|
10
42
|
oauthClient;
|
|
11
43
|
tokenVerifier;
|
|
12
|
-
constructor(config, logger, authService, socialAuthService, jwtService, sessionService, challengeHelper, clientInfoService,
|
|
44
|
+
constructor(config, logger, authService, socialAuthService, jwtService, sessionService, challengeHelper, clientInfoService,
|
|
45
|
+
// State store shared across all providers
|
|
46
|
+
stateStore, userRepository,
|
|
47
|
+
// Phone verification service (optional - only available when SMS provider is configured)
|
|
48
|
+
phoneVerificationService,
|
|
49
|
+
// Audit service (optional - only available when auditLogs.enabled is true)
|
|
50
|
+
auditService,
|
|
51
|
+
// Trusted device service (optional - only available when rememberDevices is enabled)
|
|
52
|
+
trustedDeviceService,
|
|
53
|
+
// Apple-specific token verifier (optional, fallback to TOKEN_VERIFIER)
|
|
54
|
+
tokenVerifier) {
|
|
13
55
|
super(config, logger, authService, socialAuthService, jwtService, sessionService, challengeHelper, clientInfoService, stateStore, userRepository, phoneVerificationService, auditService, trustedDeviceService);
|
|
56
|
+
// Initialize Apple OAuth client
|
|
14
57
|
const providerConfig = this.getProviderConfig();
|
|
15
58
|
if (!providerConfig || !providerConfig.enabled) {
|
|
16
59
|
this.oauthClient = null;
|
|
17
60
|
this.tokenVerifier = null;
|
|
18
|
-
return;
|
|
61
|
+
return; // Exit constructor early if disabled
|
|
19
62
|
}
|
|
20
63
|
const webClientId = Array.isArray(providerConfig.clientId) ? providerConfig.clientId[0] : providerConfig.clientId;
|
|
21
64
|
if (!webClientId) {
|
|
65
|
+
// Schema validation should catch this, but handle gracefully
|
|
22
66
|
this.oauthClient = null;
|
|
23
67
|
this.tokenVerifier = null;
|
|
24
68
|
return;
|
|
25
69
|
}
|
|
70
|
+
// Note: Apple clientSecret is optional for native flow, but required for web OAuth
|
|
71
|
+
// It's a JWT that needs to be generated from Apple Developer credentials
|
|
26
72
|
this.oauthClient = new apple_oauth_client_1.AppleOAuthClient({
|
|
27
73
|
clientId: webClientId,
|
|
28
74
|
clientSecret: providerConfig.clientSecret || '',
|
|
29
75
|
redirectUri: providerConfig.callbackUrl || '',
|
|
30
76
|
scopes: providerConfig.scopes || ['name', 'email'],
|
|
31
77
|
});
|
|
78
|
+
// Use provided token verifier or create default one
|
|
32
79
|
this.tokenVerifier =
|
|
33
80
|
tokenVerifier ||
|
|
34
81
|
new token_verifier_service_1.TokenVerifierService(config) ||
|
|
@@ -36,6 +83,12 @@ class AppleSocialAuthService extends internal_1.BaseSocialAuthProviderService {
|
|
|
36
83
|
null;
|
|
37
84
|
this.logger?.debug?.('AppleSocialAuthService initialized');
|
|
38
85
|
}
|
|
86
|
+
/**
|
|
87
|
+
* Generate OAuth authorization URL for Apple
|
|
88
|
+
*
|
|
89
|
+
* @param state - Optional state parameter for CSRF protection
|
|
90
|
+
* @returns Authorization URL for redirecting user to Apple
|
|
91
|
+
*/
|
|
39
92
|
async getAuthUrl(state) {
|
|
40
93
|
if (!this.oauthClient) {
|
|
41
94
|
throw new core_1.NAuthException(core_1.AuthErrorCode.SOCIAL_CONFIG_MISSING, 'Apple OAuth is not enabled');
|
|
@@ -43,6 +96,16 @@ class AppleSocialAuthService extends internal_1.BaseSocialAuthProviderService {
|
|
|
43
96
|
const finalState = state || this.generateState();
|
|
44
97
|
return this.oauthClient.getAuthorizationUrl(finalState);
|
|
45
98
|
}
|
|
99
|
+
/**
|
|
100
|
+
* Get OAuth user profile from callback
|
|
101
|
+
*
|
|
102
|
+
* Exchanges authorization code for access token and fetches user profile.
|
|
103
|
+
*
|
|
104
|
+
* @param code - Authorization code from Apple OAuth callback
|
|
105
|
+
* @param _state - State parameter (validated by base class)
|
|
106
|
+
* @returns User profile from Apple
|
|
107
|
+
* @protected
|
|
108
|
+
*/
|
|
46
109
|
async getOAuthProfile(code, _state) {
|
|
47
110
|
if (!this.oauthClient) {
|
|
48
111
|
throw new core_1.NAuthException(core_1.AuthErrorCode.SOCIAL_CONFIG_MISSING, 'Apple OAuth is not enabled');
|
|
@@ -51,9 +114,20 @@ class AppleSocialAuthService extends internal_1.BaseSocialAuthProviderService {
|
|
|
51
114
|
if (!providerConfig || !providerConfig.callbackUrl) {
|
|
52
115
|
throw new core_1.NAuthException(core_1.AuthErrorCode.SOCIAL_CONFIG_MISSING, 'Apple OAuth callback URL is not configured');
|
|
53
116
|
}
|
|
117
|
+
// Exchange code for access token
|
|
54
118
|
const tokens = await this.oauthClient.exchangeCodeForToken(code, providerConfig.callbackUrl);
|
|
119
|
+
// Get user profile from Apple
|
|
55
120
|
return await this.oauthClient.getUserProfile(tokens.accessToken);
|
|
56
121
|
}
|
|
122
|
+
/**
|
|
123
|
+
* Verify Apple ID token from native mobile apps
|
|
124
|
+
*
|
|
125
|
+
* @param idToken - Apple ID token from native Sign in with Apple
|
|
126
|
+
* @param _accessToken - Access token (not used for Apple)
|
|
127
|
+
* @param profileData - Optional profile data (name fields from first sign-in)
|
|
128
|
+
* @returns User profile from verified token
|
|
129
|
+
* @protected
|
|
130
|
+
*/
|
|
57
131
|
async verifyNativeToken(idToken, _accessToken, profileData) {
|
|
58
132
|
if (!this.tokenVerifier) {
|
|
59
133
|
throw new core_1.NAuthException(core_1.AuthErrorCode.SOCIAL_CONFIG_MISSING, 'Apple OAuth is not enabled');
|
|
@@ -66,18 +140,21 @@ class AppleSocialAuthService extends internal_1.BaseSocialAuthProviderService {
|
|
|
66
140
|
if (!this.tokenVerifier.verifyAppleToken) {
|
|
67
141
|
throw new core_1.NAuthException(core_1.AuthErrorCode.SOCIAL_CONFIG_MISSING, 'Apple token verifier is not available');
|
|
68
142
|
}
|
|
143
|
+
// Verify ID token with Apple's JWKS public keys
|
|
69
144
|
const verified = (await this.tokenVerifier.verifyAppleToken(idToken, clientId));
|
|
70
145
|
this.logger?.debug?.(`Verified Apple token for: ${verified.email}`);
|
|
146
|
+
// CRITICAL: Require email from all social providers for signup
|
|
71
147
|
if (!verified.email || !verified.email_verified) {
|
|
72
148
|
throw new core_1.NAuthException(core_1.AuthErrorCode.SOCIAL_EMAIL_REQUIRED, 'Email is required and must be verified by Apple.');
|
|
73
149
|
}
|
|
150
|
+
// Handle name from profileData (first-time sign-in only - Apple only sends name once)
|
|
74
151
|
const profileDataTyped = profileData;
|
|
75
152
|
return {
|
|
76
153
|
id: verified.sub,
|
|
77
154
|
email: verified.email,
|
|
78
155
|
firstName: profileDataTyped?.firstName || null,
|
|
79
156
|
lastName: profileDataTyped?.lastName || null,
|
|
80
|
-
picture: null,
|
|
157
|
+
picture: null, // Apple doesn't provide profile pictures
|
|
81
158
|
verified: verified.email_verified,
|
|
82
159
|
raw: {
|
|
83
160
|
sub: verified.sub,
|