@nauth-toolkit/social-apple 0.1.23 → 0.1.25
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.map +1 -1
- package/dist/nestjs/apple-social-auth.module.js +4 -2
- package/dist/nestjs/apple-social-auth.module.js.map +1 -1
- package/dist/src/apple-oauth.client.d.ts +3 -1
- package/dist/src/apple-oauth.client.d.ts.map +1 -1
- package/dist/src/apple-oauth.client.js +24 -11
- package/dist/src/apple-oauth.client.js.map +1 -1
- package/dist/src/apple-social-auth.service.d.ts +33 -2
- package/dist/src/apple-social-auth.service.d.ts.map +1 -1
- package/dist/src/apple-social-auth.service.js +202 -9
- package/dist/src/apple-social-auth.service.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +7 -5
|
@@ -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;
|
|
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;AAe1E,OAAO,EAIL,sBAAsB,EAGvB,MAAM,8BAA8B,CAAC;AAItC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,qBAuEa,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"}
|
|
@@ -87,8 +87,8 @@ exports.AppleSocialAuthModule = AppleSocialAuthModule = __decorate([
|
|
|
87
87
|
provide: apple_social_auth_service_1.AppleSocialAuthService,
|
|
88
88
|
useFactory: (config, logger, authService, socialAuthService, jwtService, sessionService, challengeHelper, clientInfoService, stateStore, userRepository, phoneVerificationService, auditService, // Optional - only available when auditLogs.enabled is true
|
|
89
89
|
trustedDeviceService, // Optional - only available when rememberDevices is enabled
|
|
90
|
-
tokenVerifier) => {
|
|
91
|
-
return new apple_social_auth_service_1.AppleSocialAuthService(config, logger, authService, socialAuthService, jwtService, sessionService, challengeHelper, clientInfoService, stateStore, userRepository, phoneVerificationService, auditService, trustedDeviceService, tokenVerifier);
|
|
90
|
+
tokenVerifier, socialProviderSecretRepository) => {
|
|
91
|
+
return new apple_social_auth_service_1.AppleSocialAuthService(config, logger, authService, socialAuthService, jwtService, sessionService, challengeHelper, clientInfoService, stateStore, userRepository, phoneVerificationService, auditService, trustedDeviceService, tokenVerifier, socialProviderSecretRepository);
|
|
92
92
|
},
|
|
93
93
|
inject: [
|
|
94
94
|
'NAUTH_CONFIG',
|
|
@@ -105,6 +105,8 @@ exports.AppleSocialAuthModule = AppleSocialAuthModule = __decorate([
|
|
|
105
105
|
{ token: internal_1.AuthAuditService, optional: true }, // Optional - only available when auditLogs.enabled is true
|
|
106
106
|
{ token: internal_1.TrustedDeviceService, optional: true }, // Optional - only available when rememberDevices is enabled
|
|
107
107
|
{ token: 'APPLE_TOKEN_VERIFIER', optional: true },
|
|
108
|
+
// Required when Apple is enabled (used for DB-backed JWT client secret rotation)
|
|
109
|
+
'SocialProviderSecretRepository',
|
|
108
110
|
],
|
|
109
111
|
},
|
|
110
112
|
],
|
|
@@ -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;AAC1E,qBAAqB;AACrB,
|
|
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,8CAW6B;AAC7B,sDAAsD;AACtD,2DAOsC;AACtC,0EAAkG;AAGlG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAwEI,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;IAvEjC,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,UAAiC,EACjC,cAAoC,EACpC,wBAAmD,EACnD,YAAuC,EAAE,2DAA2D;gBACpG,oBAA2C,EAAE,4DAA4D;gBACzG,aAAqC,EACrC,8BAAqE,EACrE,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,EACb,8BAA8B,CAC/B,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;oBACjD,iFAAiF;oBACjF,gCAAgC;iBACjC;aACF;SACF;QACD,OAAO,EAAE,CAAC,kDAAsB,CAAC;KAClC,CAAC;qCAG2C,kDAAsB;QAC5B,iCAAsB;GAHhD,qBAAqB,CAiBjC"}
|
|
@@ -28,6 +28,7 @@ export declare class AppleOAuthClient implements OAuthClient {
|
|
|
28
28
|
*
|
|
29
29
|
* @param code - Authorization code from Apple OAuth callback
|
|
30
30
|
* @param redirectUri - Redirect URI used in OAuth flow
|
|
31
|
+
* @param clientSecret - Optional client secret (overrides config.clientSecret)
|
|
31
32
|
* @returns Access token and optional refresh token
|
|
32
33
|
* @throws {Error} When token exchange fails
|
|
33
34
|
*
|
|
@@ -37,8 +38,9 @@ export declare class AppleOAuthClient implements OAuthClient {
|
|
|
37
38
|
* console.log(tokens.accessToken); // access_token_here
|
|
38
39
|
* ```
|
|
39
40
|
*/
|
|
40
|
-
exchangeCodeForToken(code: string, redirectUri: string): Promise<{
|
|
41
|
+
exchangeCodeForToken(code: string, redirectUri: string, clientSecret?: string): Promise<{
|
|
41
42
|
accessToken: string;
|
|
43
|
+
idToken: string;
|
|
42
44
|
refreshToken?: string;
|
|
43
45
|
expiresIn?: number;
|
|
44
46
|
}>;
|
|
@@ -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;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
|
|
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;;;;;;;;;;;;;;OAcG;IACG,oBAAoB,CACxB,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,MAAM,EACnB,YAAY,CAAC,EAAE,MAAM,GACpB,OAAO,CAAC;QACT,WAAW,EAAE,MAAM,CAAC;QACpB,OAAO,EAAE,MAAM,CAAC;QAChB,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC;IA6DF;;;;;;;;;;;;;OAaG;IACG,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAgDpE;;;;;;;;;;;OAWG;IACH,mBAAmB,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM;CAe5C"}
|
|
@@ -36,6 +36,7 @@ class AppleOAuthClient {
|
|
|
36
36
|
*
|
|
37
37
|
* @param code - Authorization code from Apple OAuth callback
|
|
38
38
|
* @param redirectUri - Redirect URI used in OAuth flow
|
|
39
|
+
* @param clientSecret - Optional client secret (overrides config.clientSecret)
|
|
39
40
|
* @returns Access token and optional refresh token
|
|
40
41
|
* @throws {Error} When token exchange fails
|
|
41
42
|
*
|
|
@@ -45,10 +46,10 @@ class AppleOAuthClient {
|
|
|
45
46
|
* console.log(tokens.accessToken); // access_token_here
|
|
46
47
|
* ```
|
|
47
48
|
*/
|
|
48
|
-
async exchangeCodeForToken(code, redirectUri) {
|
|
49
|
+
async exchangeCodeForToken(code, redirectUri, clientSecret) {
|
|
49
50
|
const params = new URLSearchParams({
|
|
50
51
|
client_id: this.config.clientId,
|
|
51
|
-
client_secret: this.config.clientSecret,
|
|
52
|
+
client_secret: clientSecret || this.config.clientSecret,
|
|
52
53
|
code,
|
|
53
54
|
grant_type: 'authorization_code',
|
|
54
55
|
redirect_uri: redirectUri,
|
|
@@ -63,13 +64,24 @@ class AppleOAuthClient {
|
|
|
63
64
|
});
|
|
64
65
|
if (!response.ok) {
|
|
65
66
|
const errorData = (await response.json());
|
|
66
|
-
|
|
67
|
+
const e = errorData;
|
|
68
|
+
throw new core_1.NAuthException(core_1.AuthErrorCode.SOCIAL_TOKEN_INVALID, `Token exchange failed: ${String(e.error_description ?? e.error ?? 'Unknown error')}`);
|
|
67
69
|
}
|
|
68
70
|
const data = (await response.json());
|
|
71
|
+
const d = data;
|
|
72
|
+
const accessToken = typeof d.access_token === 'string' ? d.access_token : null;
|
|
73
|
+
const idToken = typeof d.id_token === 'string' ? d.id_token : null;
|
|
74
|
+
const refreshToken = typeof d.refresh_token === 'string' ? d.refresh_token : undefined;
|
|
75
|
+
const expiresIn = typeof d.expires_in === 'number' ? d.expires_in : undefined;
|
|
76
|
+
if (!accessToken || !idToken) {
|
|
77
|
+
// ⚠️ SECURITY: We cannot proceed without an id_token (used for verified identity claims).
|
|
78
|
+
throw new core_1.NAuthException(core_1.AuthErrorCode.SOCIAL_TOKEN_INVALID, 'Apple token exchange returned an invalid response (missing access_token or id_token).');
|
|
79
|
+
}
|
|
69
80
|
return {
|
|
70
|
-
accessToken
|
|
71
|
-
|
|
72
|
-
|
|
81
|
+
accessToken,
|
|
82
|
+
idToken,
|
|
83
|
+
refreshToken,
|
|
84
|
+
expiresIn,
|
|
73
85
|
};
|
|
74
86
|
}
|
|
75
87
|
catch (error) {
|
|
@@ -107,17 +119,18 @@ class AppleOAuthClient {
|
|
|
107
119
|
throw new core_1.NAuthException(core_1.AuthErrorCode.INTERNAL_ERROR, `Apple API call failed: ${response.status} ${response.statusText}`);
|
|
108
120
|
}
|
|
109
121
|
const data = (await response.json());
|
|
122
|
+
const d = data;
|
|
110
123
|
// Map Apple's response to our standardized format
|
|
111
124
|
// Apple provides name in a nested object format
|
|
112
|
-
const firstName =
|
|
113
|
-
const lastName =
|
|
125
|
+
const firstName = typeof d.name?.firstName === 'string' ? d.name.firstName : null;
|
|
126
|
+
const lastName = typeof d.name?.lastName === 'string' ? d.name.lastName : null;
|
|
114
127
|
return {
|
|
115
|
-
id:
|
|
116
|
-
email:
|
|
128
|
+
id: typeof d.sub === 'string' ? d.sub : '',
|
|
129
|
+
email: typeof d.email === 'string' ? d.email : null,
|
|
117
130
|
firstName,
|
|
118
131
|
lastName,
|
|
119
132
|
picture: null, // Apple doesn't provide profile pictures
|
|
120
|
-
verified:
|
|
133
|
+
verified: d.email_verified === true || d.email_verified === 'true',
|
|
121
134
|
raw: data,
|
|
122
135
|
};
|
|
123
136
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"apple-oauth.client.js","sourceRoot":"","sources":["../../src/apple-oauth.client.ts"],"names":[],"mappings":";;;AAAA,8CAAgH;AAEhH;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAa,gBAAgB;IACV,MAAM,CAAc;IACpB,aAAa,GAAG,sCAAsC,CAAC;IACvD,gBAAgB,GAAG,yCAAyC,CAAC;IAE9E,YAAY,MAAmB;QAC7B,IAAI,CAAC,MAAM,GAAG;YACZ,MAAM,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC;YACzB,GAAG,MAAM;SACV,CAAC;IACJ,CAAC;IAED
|
|
1
|
+
{"version":3,"file":"apple-oauth.client.js","sourceRoot":"","sources":["../../src/apple-oauth.client.ts"],"names":[],"mappings":";;;AAAA,8CAAgH;AAEhH;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAa,gBAAgB;IACV,MAAM,CAAc;IACpB,aAAa,GAAG,sCAAsC,CAAC;IACvD,gBAAgB,GAAG,yCAAyC,CAAC;IAE9E,YAAY,MAAmB;QAC7B,IAAI,CAAC,MAAM,GAAG;YACZ,MAAM,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC;YACzB,GAAG,MAAM;SACV,CAAC;IACJ,CAAC;IAED;;;;;;;;;;;;;;OAcG;IACH,KAAK,CAAC,oBAAoB,CACxB,IAAY,EACZ,WAAmB,EACnB,YAAqB;QAOrB,MAAM,MAAM,GAAG,IAAI,eAAe,CAAC;YACjC,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,QAAQ;YAC/B,aAAa,EAAE,YAAY,IAAI,IAAI,CAAC,MAAM,CAAC,YAAY;YACvD,IAAI;YACJ,UAAU,EAAE,oBAAoB;YAChC,YAAY,EAAE,WAAW;SAC1B,CAAC,CAAC;QAEH,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,aAAa,EAAE;gBAC/C,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE;oBACP,cAAc,EAAE,mCAAmC;iBACpD;gBACD,IAAI,EAAE,MAAM,CAAC,QAAQ,EAAE;aACxB,CAAC,CAAC;YAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;gBACjB,MAAM,SAAS,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAY,CAAC;gBACrD,MAAM,CAAC,GAAG,SAA6D,CAAC;gBACxE,MAAM,IAAI,qBAAc,CACtB,oBAAa,CAAC,oBAAoB,EAClC,0BAA0B,MAAM,CAAC,CAAC,CAAC,iBAAiB,IAAI,CAAC,CAAC,KAAK,IAAI,eAAe,CAAC,EAAE,CACtF,CAAC;YACJ,CAAC;YAED,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAY,CAAC;YAChD,MAAM,CAAC,GAAG,IAKT,CAAC;YACF,MAAM,WAAW,GAAG,OAAO,CAAC,CAAC,YAAY,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC;YAC/E,MAAM,OAAO,GAAG,OAAO,CAAC,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC;YACnE,MAAM,YAAY,GAAG,OAAO,CAAC,CAAC,aAAa,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,SAAS,CAAC;YACvF,MAAM,SAAS,GAAG,OAAO,CAAC,CAAC,UAAU,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC;YAE9E,IAAI,CAAC,WAAW,IAAI,CAAC,OAAO,EAAE,CAAC;gBAC7B,0FAA0F;gBAC1F,MAAM,IAAI,qBAAc,CACtB,oBAAa,CAAC,oBAAoB,EAClC,uFAAuF,CACxF,CAAC;YACJ,CAAC;YAED,OAAO;gBACL,WAAW;gBACX,OAAO;gBACP,YAAY;gBACZ,SAAS;aACV,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;gBAC3B,MAAM,IAAI,qBAAc,CAAC,oBAAa,CAAC,oBAAoB,EAAE,gCAAgC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;YAChH,CAAC;YACD,MAAM,IAAI,qBAAc,CAAC,oBAAa,CAAC,oBAAoB,EAAE,4CAA4C,CAAC,CAAC;QAC7G,CAAC;IACH,CAAC;IAED;;;;;;;;;;;;;OAaG;IACH,KAAK,CAAC,cAAc,CAAC,WAAmB;QACtC,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,gBAAgB,EAAE;gBAClD,OAAO,EAAE;oBACP,aAAa,EAAE,UAAU,WAAW,EAAE;iBACvC;aACF,CAAC,CAAC;YAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;gBACjB,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;oBAC5B,MAAM,IAAI,qBAAc,CAAC,oBAAa,CAAC,oBAAoB,EAAE,iCAAiC,CAAC,CAAC;gBAClG,CAAC;gBACD,MAAM,IAAI,qBAAc,CACtB,oBAAa,CAAC,cAAc,EAC5B,0BAA0B,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,UAAU,EAAE,CACnE,CAAC;YACJ,CAAC;YAED,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAY,CAAC;YAChD,MAAM,CAAC,GAAG,IAKT,CAAC;YAEF,kDAAkD;YAClD,gDAAgD;YAChD,MAAM,SAAS,GAAG,OAAO,CAAC,CAAC,IAAI,EAAE,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC;YAClF,MAAM,QAAQ,GAAG,OAAO,CAAC,CAAC,IAAI,EAAE,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC;YAE/E,OAAO;gBACL,EAAE,EAAE,OAAO,CAAC,CAAC,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE;gBAC1C,KAAK,EAAE,OAAO,CAAC,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI;gBACnD,SAAS;gBACT,QAAQ;gBACR,OAAO,EAAE,IAAI,EAAE,yCAAyC;gBACxD,QAAQ,EAAE,CAAC,CAAC,cAAc,KAAK,IAAI,IAAI,CAAC,CAAC,cAAc,KAAK,MAAM;gBAClE,GAAG,EAAE,IAA+B;aACrC,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;gBAC3B,MAAM,IAAI,qBAAc,CAAC,oBAAa,CAAC,cAAc,EAAE,+BAA+B,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;YACzG,CAAC;YACD,MAAM,IAAI,qBAAc,CAAC,oBAAa,CAAC,cAAc,EAAE,2CAA2C,CAAC,CAAC;QACtG,CAAC;IACH,CAAC;IAED;;;;;;;;;;;OAWG;IACH,mBAAmB,CAAC,KAAc;QAChC,MAAM,MAAM,GAAG,IAAI,eAAe,CAAC;YACjC,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,QAAQ;YAC/B,YAAY,EAAE,IAAI,CAAC,MAAM,CAAC,WAAW;YACrC,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,YAAY;YACpD,aAAa,EAAE,MAAM;YACrB,aAAa,EAAE,WAAW;SAC3B,CAAC,CAAC;QAEH,IAAI,KAAK,EAAE,CAAC;YACV,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;QAChC,CAAC;QAED,OAAO,4CAA4C,MAAM,CAAC,QAAQ,EAAE,EAAE,CAAC;IACzE,CAAC;CACF;AA1LD,4CA0LC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AuthService, SocialAuthService, ClientInfoService, NAuthConfig, NAuthLogger, OAuthUserProfile, PhoneVerificationService, ISocialAuthProviderService, ITokenVerifierService, BaseUser, ISocialAuthStateStore } from '@nauth-toolkit/core';
|
|
1
|
+
import { AuthService, SocialAuthService, ClientInfoService, NAuthConfig, NAuthLogger, OAuthUserProfile, PhoneVerificationService, ISocialAuthProviderService, ITokenVerifierService, BaseUser, ISocialAuthStateStore, BaseSocialProviderSecret } from '@nauth-toolkit/core';
|
|
2
2
|
import { BaseSocialAuthProviderService, JwtService, SessionService, AuthChallengeHelperService, AuthAuditService, // Internal version with recordEvent()
|
|
3
3
|
TrustedDeviceService } from '@nauth-toolkit/core/internal';
|
|
4
4
|
import { Repository } from 'typeorm';
|
|
@@ -36,7 +36,37 @@ export declare class AppleSocialAuthService extends BaseSocialAuthProviderServic
|
|
|
36
36
|
readonly providerName = "apple";
|
|
37
37
|
private readonly oauthClient;
|
|
38
38
|
private readonly tokenVerifier;
|
|
39
|
-
|
|
39
|
+
private readonly socialProviderSecretRepository;
|
|
40
|
+
private joseModulePromise;
|
|
41
|
+
constructor(config: NAuthConfig, logger: NAuthLogger, authService: AuthService, socialAuthService: SocialAuthService, jwtService: JwtService, sessionService: SessionService, challengeHelper: AuthChallengeHelperService, clientInfoService: ClientInfoService, stateStore: ISocialAuthStateStore, userRepository: Repository<BaseUser>, phoneVerificationService?: PhoneVerificationService, auditService?: AuthAuditService, trustedDeviceService?: TrustedDeviceService, tokenVerifier?: ITokenVerifierService, socialProviderSecretRepository?: Repository<BaseSocialProviderSecret> | null);
|
|
42
|
+
/**
|
|
43
|
+
* Lazy-load jose (ESM-only) in a CJS-compatible way.
|
|
44
|
+
*
|
|
45
|
+
* @returns Promise resolving to jose module
|
|
46
|
+
*/
|
|
47
|
+
private getJose;
|
|
48
|
+
/**
|
|
49
|
+
* Generate Apple JWT client secret from configuration
|
|
50
|
+
*
|
|
51
|
+
* Creates a JWT signed with ES256 using the provided .p8 private key.
|
|
52
|
+
* The JWT is valid for 180 days (Apple's maximum).
|
|
53
|
+
*
|
|
54
|
+
* @param providerConfig - Apple provider configuration
|
|
55
|
+
* @returns Generated JWT client secret
|
|
56
|
+
* @throws {NAuthException} If required configuration is missing
|
|
57
|
+
*/
|
|
58
|
+
private generateAppleJWTClientSecret;
|
|
59
|
+
/**
|
|
60
|
+
* Get or refresh Apple JWT client secret from database
|
|
61
|
+
*
|
|
62
|
+
* Retrieves the stored JWT from the database. If it doesn't exist or has less than
|
|
63
|
+
* 30 days until expiration, generates a new JWT and stores it.
|
|
64
|
+
*
|
|
65
|
+
* @param providerConfig - Apple provider configuration
|
|
66
|
+
* @returns JWT client secret
|
|
67
|
+
* @throws {NAuthException} If JWT generation fails or repository is not available
|
|
68
|
+
*/
|
|
69
|
+
private getOrRefreshAppleJWTClientSecret;
|
|
40
70
|
/**
|
|
41
71
|
* Generate OAuth authorization URL for Apple
|
|
42
72
|
*
|
|
@@ -48,6 +78,7 @@ export declare class AppleSocialAuthService extends BaseSocialAuthProviderServic
|
|
|
48
78
|
* Get OAuth user profile from callback
|
|
49
79
|
*
|
|
50
80
|
* Exchanges authorization code for access token and fetches user profile.
|
|
81
|
+
* Automatically refreshes Apple JWT client secret if needed.
|
|
51
82
|
*
|
|
52
83
|
* @param code - Authorization code from Apple OAuth callback
|
|
53
84
|
* @param _state - State parameter (validated by base class)
|
|
@@ -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,EACR,qBAAqB,
|
|
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,EACR,qBAAqB,EACrB,wBAAwB,EACzB,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;AAarC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;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;IAC7D,OAAO,CAAC,QAAQ,CAAC,8BAA8B,CAA8C;IAC7F,OAAO,CAAC,iBAAiB,CAAoC;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,qBAAqB,EACjC,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,EAErC,8BAA8B,CAAC,EAAE,UAAU,CAAC,wBAAwB,CAAC,GAAG,IAAI;IAsE9E;;;;OAIG;YACW,OAAO;IAOrB;;;;;;;;;OASG;YACW,4BAA4B;IAkE1C;;;;;;;;;OASG;YACW,gCAAgC;IAiD9C;;;;;OAKG;IACG,UAAU,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAQjD;;;;;;;;;;OAUG;cACa,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAkDxF;;;;;;;;OAQG;cACa,iBAAiB,CAC/B,OAAO,EAAE,MAAM,EACf,YAAY,CAAC,EAAE,MAAM,EACrB,WAAW,CAAC,EAAE,OAAO,GACpB,OAAO,CAAC,gBAAgB,CAAC;CA0C7B"}
|
|
@@ -1,4 +1,37 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
2
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
36
|
exports.AppleSocialAuthService = void 0;
|
|
4
37
|
// Public API imports
|
|
@@ -41,6 +74,8 @@ class AppleSocialAuthService extends internal_1.BaseSocialAuthProviderService {
|
|
|
41
74
|
providerName = 'apple';
|
|
42
75
|
oauthClient;
|
|
43
76
|
tokenVerifier;
|
|
77
|
+
socialProviderSecretRepository;
|
|
78
|
+
joseModulePromise = null;
|
|
44
79
|
constructor(config, logger, authService, socialAuthService, jwtService, sessionService, challengeHelper, clientInfoService,
|
|
45
80
|
// State store shared across all providers
|
|
46
81
|
stateStore, userRepository,
|
|
@@ -51,8 +86,12 @@ class AppleSocialAuthService extends internal_1.BaseSocialAuthProviderService {
|
|
|
51
86
|
// Trusted device service (optional - only available when rememberDevices is enabled)
|
|
52
87
|
trustedDeviceService,
|
|
53
88
|
// Apple-specific token verifier (optional, fallback to TOKEN_VERIFIER)
|
|
54
|
-
tokenVerifier
|
|
89
|
+
tokenVerifier,
|
|
90
|
+
// Repository for storing Apple JWT client secrets (optional, for JWT rotation)
|
|
91
|
+
socialProviderSecretRepository) {
|
|
55
92
|
super(config, logger, authService, socialAuthService, jwtService, sessionService, challengeHelper, clientInfoService, stateStore, userRepository, phoneVerificationService, auditService, trustedDeviceService);
|
|
93
|
+
// Store repository for JWT rotation
|
|
94
|
+
this.socialProviderSecretRepository = socialProviderSecretRepository || null;
|
|
56
95
|
// Initialize Apple OAuth client
|
|
57
96
|
const providerConfig = this.getProviderConfig();
|
|
58
97
|
if (!providerConfig || !providerConfig.enabled) {
|
|
@@ -60,6 +99,17 @@ class AppleSocialAuthService extends internal_1.BaseSocialAuthProviderService {
|
|
|
60
99
|
this.tokenVerifier = null;
|
|
61
100
|
return; // Exit constructor early if disabled
|
|
62
101
|
}
|
|
102
|
+
// ============================================================================
|
|
103
|
+
// Apple JWT Rotation Dependency Validation (web OAuth)
|
|
104
|
+
// ============================================================================
|
|
105
|
+
// WHY: Apple is an optional provider. We only require the DB repository when Apple is enabled.
|
|
106
|
+
// This makes misconfiguration fail fast on startup (module init), not during the callback.
|
|
107
|
+
// ============================================================================
|
|
108
|
+
if (!this.socialProviderSecretRepository) {
|
|
109
|
+
throw new core_1.NAuthException(core_1.AuthErrorCode.SOCIAL_CONFIG_MISSING, 'Apple Sign-In is enabled but SocialProviderSecretRepository is not available. ' +
|
|
110
|
+
'Ensure your TypeORM DataSource includes the SocialProviderSecret entity (via getNAuthEntities()) ' +
|
|
111
|
+
'and that @nauth-toolkit/nestjs AuthModule is imported.');
|
|
112
|
+
}
|
|
63
113
|
const webClientId = Array.isArray(providerConfig.clientId) ? providerConfig.clientId[0] : providerConfig.clientId;
|
|
64
114
|
if (!webClientId) {
|
|
65
115
|
// Schema validation should catch this, but handle gracefully
|
|
@@ -67,11 +117,10 @@ class AppleSocialAuthService extends internal_1.BaseSocialAuthProviderService {
|
|
|
67
117
|
this.tokenVerifier = null;
|
|
68
118
|
return;
|
|
69
119
|
}
|
|
70
|
-
//
|
|
71
|
-
// It's a JWT that needs to be generated from Apple Developer credentials
|
|
120
|
+
// Initialize OAuth client without clientSecret (will be provided dynamically)
|
|
72
121
|
this.oauthClient = new apple_oauth_client_1.AppleOAuthClient({
|
|
73
122
|
clientId: webClientId,
|
|
74
|
-
clientSecret:
|
|
123
|
+
clientSecret: '', // Will be provided dynamically per request
|
|
75
124
|
redirectUri: providerConfig.callbackUrl || '',
|
|
76
125
|
scopes: providerConfig.scopes || ['name', 'email'],
|
|
77
126
|
});
|
|
@@ -83,6 +132,117 @@ class AppleSocialAuthService extends internal_1.BaseSocialAuthProviderService {
|
|
|
83
132
|
null;
|
|
84
133
|
this.logger?.debug?.('AppleSocialAuthService initialized');
|
|
85
134
|
}
|
|
135
|
+
/**
|
|
136
|
+
* Lazy-load jose (ESM-only) in a CJS-compatible way.
|
|
137
|
+
*
|
|
138
|
+
* @returns Promise resolving to jose module
|
|
139
|
+
*/
|
|
140
|
+
async getJose() {
|
|
141
|
+
if (!this.joseModulePromise) {
|
|
142
|
+
this.joseModulePromise = Promise.resolve().then(() => __importStar(require('jose')));
|
|
143
|
+
}
|
|
144
|
+
return await this.joseModulePromise;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Generate Apple JWT client secret from configuration
|
|
148
|
+
*
|
|
149
|
+
* Creates a JWT signed with ES256 using the provided .p8 private key.
|
|
150
|
+
* The JWT is valid for 180 days (Apple's maximum).
|
|
151
|
+
*
|
|
152
|
+
* @param providerConfig - Apple provider configuration
|
|
153
|
+
* @returns Generated JWT client secret
|
|
154
|
+
* @throws {NAuthException} If required configuration is missing
|
|
155
|
+
*/
|
|
156
|
+
async generateAppleJWTClientSecret(providerConfig) {
|
|
157
|
+
if (!providerConfig.teamId || !providerConfig.keyId || !providerConfig.privateKeyPem) {
|
|
158
|
+
throw new core_1.NAuthException(core_1.AuthErrorCode.SOCIAL_CONFIG_MISSING, 'Apple configuration requires teamId, keyId, and privateKeyPem for web OAuth');
|
|
159
|
+
}
|
|
160
|
+
const clientId = Array.isArray(providerConfig.clientId) ? providerConfig.clientId[0] : providerConfig.clientId;
|
|
161
|
+
if (!clientId) {
|
|
162
|
+
throw new core_1.NAuthException(core_1.AuthErrorCode.SOCIAL_CONFIG_MISSING, 'Apple clientId is required');
|
|
163
|
+
}
|
|
164
|
+
const jose = await this.getJose();
|
|
165
|
+
// Normalize the private key format
|
|
166
|
+
// Handle both formats: with \n escape sequences or actual newlines, or single-line
|
|
167
|
+
let normalizedKey = providerConfig.privateKeyPem;
|
|
168
|
+
// Replace literal \n with actual newlines (for environment variables with escape sequences)
|
|
169
|
+
normalizedKey = normalizedKey.replace(/\\n/g, '\n');
|
|
170
|
+
// Ensure proper PEM format with newlines if missing
|
|
171
|
+
if (!normalizedKey.includes('\n')) {
|
|
172
|
+
// Single-line key: insert newlines after header and before footer
|
|
173
|
+
normalizedKey = normalizedKey.replace(/-----BEGIN PRIVATE KEY-----(.+)-----END PRIVATE KEY-----/, '-----BEGIN PRIVATE KEY-----\n$1\n-----END PRIVATE KEY-----');
|
|
174
|
+
}
|
|
175
|
+
// Parse the private key
|
|
176
|
+
// importPKCS8 returns a private key that can be used for signing
|
|
177
|
+
let privateKey;
|
|
178
|
+
try {
|
|
179
|
+
privateKey = await jose.importPKCS8(normalizedKey, 'ES256');
|
|
180
|
+
}
|
|
181
|
+
catch (error) {
|
|
182
|
+
throw new core_1.NAuthException(core_1.AuthErrorCode.SOCIAL_CONFIG_MISSING, `Failed to parse Apple private key: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
183
|
+
}
|
|
184
|
+
// Generate JWT with 180 days expiration (Apple's maximum)
|
|
185
|
+
const now = Math.floor(Date.now() / 1000);
|
|
186
|
+
const expiresIn = 180 * 24 * 60 * 60; // 180 days in seconds
|
|
187
|
+
const jwt = await new jose.SignJWT({
|
|
188
|
+
iss: providerConfig.teamId,
|
|
189
|
+
iat: now,
|
|
190
|
+
exp: now + expiresIn,
|
|
191
|
+
aud: 'https://appleid.apple.com',
|
|
192
|
+
sub: clientId,
|
|
193
|
+
})
|
|
194
|
+
.setProtectedHeader({
|
|
195
|
+
alg: 'ES256',
|
|
196
|
+
kid: providerConfig.keyId,
|
|
197
|
+
})
|
|
198
|
+
.sign(privateKey);
|
|
199
|
+
return jwt;
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Get or refresh Apple JWT client secret from database
|
|
203
|
+
*
|
|
204
|
+
* Retrieves the stored JWT from the database. If it doesn't exist or has less than
|
|
205
|
+
* 30 days until expiration, generates a new JWT and stores it.
|
|
206
|
+
*
|
|
207
|
+
* @param providerConfig - Apple provider configuration
|
|
208
|
+
* @returns JWT client secret
|
|
209
|
+
* @throws {NAuthException} If JWT generation fails or repository is not available
|
|
210
|
+
*/
|
|
211
|
+
async getOrRefreshAppleJWTClientSecret(providerConfig) {
|
|
212
|
+
if (!this.socialProviderSecretRepository) {
|
|
213
|
+
throw new core_1.NAuthException(core_1.AuthErrorCode.SOCIAL_CONFIG_MISSING, 'SocialProviderSecretRepository is required for Apple JWT rotation. Ensure the entity is registered in your database adapter.');
|
|
214
|
+
}
|
|
215
|
+
const provider = 'apple';
|
|
216
|
+
const now = new Date();
|
|
217
|
+
const refreshThreshold = new Date(now.getTime() + 30 * 24 * 60 * 60 * 1000); // 30 days from now
|
|
218
|
+
// Try to find existing secret
|
|
219
|
+
let secret = await this.socialProviderSecretRepository.findOne({
|
|
220
|
+
where: { provider },
|
|
221
|
+
});
|
|
222
|
+
// Check if we need to refresh (missing or expires within 30 days)
|
|
223
|
+
if (!secret || secret.expiresAt <= refreshThreshold) {
|
|
224
|
+
// Generate new JWT
|
|
225
|
+
const jwt = await this.generateAppleJWTClientSecret(providerConfig);
|
|
226
|
+
const expiresAt = new Date(now.getTime() + 180 * 24 * 60 * 60 * 1000); // 180 days from now
|
|
227
|
+
if (secret) {
|
|
228
|
+
// Update existing record
|
|
229
|
+
secret.clientSecretJwt = jwt;
|
|
230
|
+
secret.expiresAt = expiresAt;
|
|
231
|
+
await this.socialProviderSecretRepository.save(secret);
|
|
232
|
+
}
|
|
233
|
+
else {
|
|
234
|
+
// Create new record
|
|
235
|
+
secret = this.socialProviderSecretRepository.create({
|
|
236
|
+
provider,
|
|
237
|
+
clientSecretJwt: jwt,
|
|
238
|
+
expiresAt,
|
|
239
|
+
});
|
|
240
|
+
await this.socialProviderSecretRepository.save(secret);
|
|
241
|
+
}
|
|
242
|
+
this.logger?.debug?.('Generated and stored new Apple JWT client secret');
|
|
243
|
+
}
|
|
244
|
+
return secret.clientSecretJwt;
|
|
245
|
+
}
|
|
86
246
|
/**
|
|
87
247
|
* Generate OAuth authorization URL for Apple
|
|
88
248
|
*
|
|
@@ -100,6 +260,7 @@ class AppleSocialAuthService extends internal_1.BaseSocialAuthProviderService {
|
|
|
100
260
|
* Get OAuth user profile from callback
|
|
101
261
|
*
|
|
102
262
|
* Exchanges authorization code for access token and fetches user profile.
|
|
263
|
+
* Automatically refreshes Apple JWT client secret if needed.
|
|
103
264
|
*
|
|
104
265
|
* @param code - Authorization code from Apple OAuth callback
|
|
105
266
|
* @param _state - State parameter (validated by base class)
|
|
@@ -114,10 +275,40 @@ class AppleSocialAuthService extends internal_1.BaseSocialAuthProviderService {
|
|
|
114
275
|
if (!providerConfig || !providerConfig.callbackUrl) {
|
|
115
276
|
throw new core_1.NAuthException(core_1.AuthErrorCode.SOCIAL_CONFIG_MISSING, 'Apple OAuth callback URL is not configured');
|
|
116
277
|
}
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
278
|
+
if (!this.tokenVerifier?.verifyAppleToken) {
|
|
279
|
+
throw new core_1.NAuthException(core_1.AuthErrorCode.SOCIAL_CONFIG_MISSING, 'Apple token verifier is not available');
|
|
280
|
+
}
|
|
281
|
+
// Get or refresh JWT client secret
|
|
282
|
+
const clientSecret = await this.getOrRefreshAppleJWTClientSecret(providerConfig);
|
|
283
|
+
// Exchange code for tokens (includes id_token)
|
|
284
|
+
const tokens = await this.oauthClient.exchangeCodeForToken(code, providerConfig.callbackUrl, clientSecret);
|
|
285
|
+
const clientId = Array.isArray(providerConfig.clientId)
|
|
286
|
+
? providerConfig.clientId[0]
|
|
287
|
+
: providerConfig.clientId || '';
|
|
288
|
+
if (!clientId) {
|
|
289
|
+
throw new core_1.NAuthException(core_1.AuthErrorCode.SOCIAL_CONFIG_MISSING, 'Apple clientId is required');
|
|
290
|
+
}
|
|
291
|
+
// Apple does not reliably provide a UserInfo endpoint for web OAuth.
|
|
292
|
+
// The standard approach is to verify and read claims from the id_token.
|
|
293
|
+
const verified = (await this.tokenVerifier.verifyAppleToken(tokens.idToken, clientId));
|
|
294
|
+
// CRITICAL: Require email from all social providers for signup
|
|
295
|
+
if (!verified.email || !verified.email_verified) {
|
|
296
|
+
throw new core_1.NAuthException(core_1.AuthErrorCode.SOCIAL_EMAIL_REQUIRED, 'Email is required and must be verified by Apple.');
|
|
297
|
+
}
|
|
298
|
+
return {
|
|
299
|
+
id: verified.sub,
|
|
300
|
+
email: verified.email,
|
|
301
|
+
firstName: null, // Apple only returns name once (via callback profileData; not available in redirect-first flow today)
|
|
302
|
+
lastName: null,
|
|
303
|
+
picture: null,
|
|
304
|
+
verified: verified.email_verified,
|
|
305
|
+
raw: {
|
|
306
|
+
sub: verified.sub,
|
|
307
|
+
email: verified.email,
|
|
308
|
+
email_verified: verified.email_verified,
|
|
309
|
+
is_private_email: verified.is_private_email,
|
|
310
|
+
},
|
|
311
|
+
};
|
|
121
312
|
}
|
|
122
313
|
/**
|
|
123
314
|
* Verify Apple ID token from native mobile apps
|
|
@@ -136,7 +327,9 @@ class AppleSocialAuthService extends internal_1.BaseSocialAuthProviderService {
|
|
|
136
327
|
if (!providerConfig) {
|
|
137
328
|
throw new core_1.NAuthException(core_1.AuthErrorCode.SOCIAL_CONFIG_MISSING, 'Apple OAuth is not configured');
|
|
138
329
|
}
|
|
139
|
-
const clientId = Array.isArray(providerConfig.clientId)
|
|
330
|
+
const clientId = Array.isArray(providerConfig.clientId)
|
|
331
|
+
? providerConfig.clientId[0]
|
|
332
|
+
: providerConfig.clientId || '';
|
|
140
333
|
if (!this.tokenVerifier.verifyAppleToken) {
|
|
141
334
|
throw new core_1.NAuthException(core_1.AuthErrorCode.SOCIAL_CONFIG_MISSING, 'Apple token verifier is not available');
|
|
142
335
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"apple-social-auth.service.js","sourceRoot":"","sources":["../../src/apple-social-auth.service.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"apple-social-auth.service.js","sourceRoot":"","sources":["../../src/apple-social-auth.service.ts"],"names":[],"mappings":"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"}
|