@nauth-toolkit/social-google 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/google-social-auth.module.d.ts +38 -0
- package/dist/nestjs/google-social-auth.module.d.ts.map +1 -1
- package/dist/nestjs/google-social-auth.module.js +54 -3
- package/dist/nestjs/google-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/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/google-oauth.client.d.ts +59 -0
- package/dist/src/google-oauth.client.d.ts.map +1 -1
- package/dist/src/google-oauth.client.js +62 -0
- package/dist/src/google-oauth.client.js.map +1 -1
- package/dist/src/google-social-auth.service.d.ts +43 -1
- package/dist/src/google-social-auth.service.d.ts.map +1 -1
- package/dist/src/google-social-auth.service.js +63 -1
- package/dist/src/google-social-auth.service.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 +44 -1
- package/dist/src/token-verifier.service.js.map +1 -1
- package/dist/src/verified-token-profile.interface.d.ts +24 -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,24 +1,70 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.GoogleSocialAuthService = 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 google_oauth_client_1 = require("./google-oauth.client");
|
|
7
9
|
const token_verifier_service_1 = require("./token-verifier.service");
|
|
10
|
+
/**
|
|
11
|
+
* Google Social Authentication Service (Platform-Agnostic)
|
|
12
|
+
*
|
|
13
|
+
* Handles Google 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-google/nestjs` for NestJS integration.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```typescript
|
|
23
|
+
* // Direct instantiation (platform-agnostic)
|
|
24
|
+
* const googleAuth = new GoogleSocialAuthService(
|
|
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 GoogleSocialAuthService extends internal_1.BaseSocialAuthProviderService {
|
|
9
41
|
providerName = 'google';
|
|
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
|
+
// Google-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 Google OAuth client only if enabled
|
|
14
57
|
const providerConfig = this.getProviderConfig();
|
|
15
58
|
if (!providerConfig || !providerConfig.enabled) {
|
|
59
|
+
// Service can exist but be disabled - don't initialize OAuth client
|
|
60
|
+
// Schema validation ensures credentials are present when enabled=true
|
|
16
61
|
this.oauthClient = null;
|
|
17
62
|
this.tokenVerifier = null;
|
|
18
63
|
return;
|
|
19
64
|
}
|
|
20
65
|
const webClientId = Array.isArray(providerConfig.clientId) ? providerConfig.clientId[0] : providerConfig.clientId;
|
|
21
66
|
if (!webClientId || !providerConfig.clientSecret) {
|
|
67
|
+
// Schema validation should catch this, but double-check for safety
|
|
22
68
|
throw new core_1.NAuthException(core_1.AuthErrorCode.SOCIAL_CONFIG_MISSING, 'Google OAuth clientId and clientSecret are required when enabled');
|
|
23
69
|
}
|
|
24
70
|
this.oauthClient = new google_oauth_client_1.GoogleOAuthClient({
|
|
@@ -27,9 +73,13 @@ class GoogleSocialAuthService extends internal_1.BaseSocialAuthProviderService {
|
|
|
27
73
|
redirectUri: providerConfig.callbackUrl || '',
|
|
28
74
|
scopes: providerConfig.scopes || ['openid', 'email', 'profile'],
|
|
29
75
|
});
|
|
76
|
+
// Use provided token verifier or create default one
|
|
30
77
|
this.tokenVerifier = tokenVerifier || new token_verifier_service_1.TokenVerifierService(config);
|
|
31
78
|
this.logger?.debug?.('GoogleSocialAuthService initialized');
|
|
32
79
|
}
|
|
80
|
+
/**
|
|
81
|
+
* Generate OAuth authorization URL for Google
|
|
82
|
+
*/
|
|
33
83
|
async getAuthUrl(state) {
|
|
34
84
|
if (!this.oauthClient) {
|
|
35
85
|
throw new core_1.NAuthException(core_1.AuthErrorCode.SOCIAL_CONFIG_MISSING, 'Google OAuth is not enabled');
|
|
@@ -37,6 +87,11 @@ class GoogleSocialAuthService extends internal_1.BaseSocialAuthProviderService {
|
|
|
37
87
|
const finalState = state || this.generateState();
|
|
38
88
|
return this.oauthClient.getAuthorizationUrl(finalState);
|
|
39
89
|
}
|
|
90
|
+
/**
|
|
91
|
+
* Get OAuth user profile from callback
|
|
92
|
+
*
|
|
93
|
+
* Exchanges authorization code for access token and fetches user profile.
|
|
94
|
+
*/
|
|
40
95
|
async getOAuthProfile(code, _state) {
|
|
41
96
|
if (!this.oauthClient) {
|
|
42
97
|
throw new core_1.NAuthException(core_1.AuthErrorCode.SOCIAL_CONFIG_MISSING, 'Google OAuth is not enabled');
|
|
@@ -45,9 +100,14 @@ class GoogleSocialAuthService extends internal_1.BaseSocialAuthProviderService {
|
|
|
45
100
|
if (!providerConfig || !providerConfig.callbackUrl) {
|
|
46
101
|
throw new core_1.NAuthException(core_1.AuthErrorCode.SOCIAL_CONFIG_MISSING, 'Google OAuth callback URL is not configured');
|
|
47
102
|
}
|
|
103
|
+
// Exchange code for access token
|
|
48
104
|
const tokens = await this.oauthClient.exchangeCodeForToken(code, providerConfig.callbackUrl);
|
|
105
|
+
// Get user profile from Google
|
|
49
106
|
return await this.oauthClient.getUserProfile(tokens.accessToken);
|
|
50
107
|
}
|
|
108
|
+
/**
|
|
109
|
+
* Verify Google ID token from native mobile apps
|
|
110
|
+
*/
|
|
51
111
|
async verifyNativeToken(idToken, _accessToken, profileData) {
|
|
52
112
|
const providerConfig = this.getProviderConfig();
|
|
53
113
|
if (!providerConfig) {
|
|
@@ -57,8 +117,10 @@ class GoogleSocialAuthService extends internal_1.BaseSocialAuthProviderService {
|
|
|
57
117
|
if (!this.tokenVerifier?.verifyGoogleToken) {
|
|
58
118
|
throw new core_1.NAuthException(core_1.AuthErrorCode.SOCIAL_CONFIG_MISSING, 'Google token verifier is not available');
|
|
59
119
|
}
|
|
120
|
+
// Verify ID token with Google's public keys
|
|
60
121
|
const verified = (await this.tokenVerifier.verifyGoogleToken(idToken, clientIds));
|
|
61
122
|
this.logger?.debug?.(`Verified Google token for: ${verified.email}`);
|
|
123
|
+
// CRITICAL: Require email from all social providers for signup
|
|
62
124
|
if (!verified.email || !verified.email_verified) {
|
|
63
125
|
throw new core_1.NAuthException(core_1.AuthErrorCode.SOCIAL_EMAIL_REQUIRED, 'Email is required and must be verified by Google.');
|
|
64
126
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"google-social-auth.service.js","sourceRoot":"","sources":["../../src/google-social-auth.service.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"google-social-auth.service.js","sourceRoot":"","sources":["../../src/google-social-auth.service.ts"],"names":[],"mappings":"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"}
|
package/dist/src/index.d.ts
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @nauth-toolkit/social-google
|
|
3
|
+
*
|
|
4
|
+
* Platform-agnostic Google OAuth provider for nauth-toolkit.
|
|
5
|
+
* For NestJS integration, use '@nauth-toolkit/social-google/nestjs'
|
|
6
|
+
*/
|
|
1
7
|
export { GoogleOAuthClient } from './google-oauth.client';
|
|
2
8
|
export { TokenVerifierService } from './token-verifier.service';
|
|
3
9
|
export { GoogleSocialAuthService } from './google-social-auth.service';
|
package/dist/src/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AACvE,OAAO,EAAE,0BAA0B,EAAE,MAAM,oCAAoC,CAAC;AAChF,cAAc,wBAAwB,CAAC"}
|
package/dist/src/index.js
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @nauth-toolkit/social-google
|
|
4
|
+
*
|
|
5
|
+
* Platform-agnostic Google OAuth provider for nauth-toolkit.
|
|
6
|
+
* For NestJS integration, use '@nauth-toolkit/social-google/nestjs'
|
|
7
|
+
*/
|
|
2
8
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
9
|
if (k2 === undefined) k2 = k;
|
|
4
10
|
var desc = Object.getOwnPropertyDescriptor(m, k);
|
package/dist/src/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;;;;;;;;;;;;;;;AAEH,6DAA0D;AAAjD,wHAAA,iBAAiB,OAAA;AAC1B,mEAAgE;AAAvD,8HAAA,oBAAoB,OAAA;AAC7B,2EAAuE;AAA9D,qIAAA,uBAAuB,OAAA;AAEhC,yDAAuC"}
|
|
@@ -1,6 +1,30 @@
|
|
|
1
1
|
import { NAuthConfig, ITokenVerifierService } from '@nauth-toolkit/core';
|
|
2
2
|
import { VerifiedGoogleTokenProfile } from './verified-token-profile.interface';
|
|
3
|
+
/**
|
|
4
|
+
* jose module type (ESM-only dependency).
|
|
5
|
+
*
|
|
6
|
+
* IMPORTANT: `jose@6` is ESM-only. This package is compiled to CommonJS by default,
|
|
7
|
+
* so we load jose via dynamic import to avoid `ERR_REQUIRE_ESM` at runtime.
|
|
8
|
+
*/
|
|
3
9
|
type JoseModule = typeof import('jose');
|
|
10
|
+
/**
|
|
11
|
+
* Token Verifier Service for Google OAuth (Platform-Agnostic)
|
|
12
|
+
*
|
|
13
|
+
* Handles secure verification of Google ID tokens using JWKS public keys.
|
|
14
|
+
* Uses cryptographic signature verification to ensure tokens are authentic.
|
|
15
|
+
*
|
|
16
|
+
* Security Features:
|
|
17
|
+
* - Google: Verifies JWT signature with Google's JWKS public keys using jwks-rsa
|
|
18
|
+
*
|
|
19
|
+
* This is a plain TypeScript class with no framework dependencies.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```typescript
|
|
23
|
+
* const verifier = new TokenVerifierService(config);
|
|
24
|
+
* const profile = await verifier.verifyGoogleToken(idToken, clientId);
|
|
25
|
+
* console.log(profile.email); // Verified email from Google
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
4
28
|
export declare class TokenVerifierService implements ITokenVerifierService {
|
|
5
29
|
private googleJWKS;
|
|
6
30
|
private readonly logger;
|
|
@@ -9,6 +33,27 @@ export declare class TokenVerifierService implements ITokenVerifierService {
|
|
|
9
33
|
constructor(config: NAuthConfig, loadJose?: () => Promise<JoseModule>);
|
|
10
34
|
private getJose;
|
|
11
35
|
private getGoogleJWKS;
|
|
36
|
+
/**
|
|
37
|
+
* Verify Google ID token with JWT signature validation
|
|
38
|
+
*
|
|
39
|
+
* Fetches Google's public keys from their JWKS endpoint and verifies the
|
|
40
|
+
* JWT signature to ensure authenticity.
|
|
41
|
+
*
|
|
42
|
+
* @param idToken - ID token from Google OAuth
|
|
43
|
+
* @param clientId - Google OAuth client ID for audience validation (supports multiple IDs)
|
|
44
|
+
* @returns Verified user profile data
|
|
45
|
+
* @throws {BadRequestException} When token is invalid, expired, or signature fails
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* ```typescript
|
|
49
|
+
* try {
|
|
50
|
+
* const profile = await verifier.verifyGoogleToken(idToken, ['web-client-id', 'ios-client-id']);
|
|
51
|
+
* console.log(`Verified email: ${profile.email}`);
|
|
52
|
+
* } catch (error) {
|
|
53
|
+
* console.error('Token verification failed:', error.message);
|
|
54
|
+
* }
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
12
57
|
verifyGoogleToken(idToken: string, clientId: string | string[]): Promise<VerifiedGoogleTokenProfile>;
|
|
13
58
|
}
|
|
14
59
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"token-verifier.service.d.ts","sourceRoot":"","sources":["../../src/token-verifier.service.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAA8C,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AACrH,OAAO,EAAE,0BAA0B,EAAE,MAAM,oCAAoC,CAAC;
|
|
1
|
+
{"version":3,"file":"token-verifier.service.d.ts","sourceRoot":"","sources":["../../src/token-verifier.service.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAA8C,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AACrH,OAAO,EAAE,0BAA0B,EAAE,MAAM,oCAAoC,CAAC;AAEhF;;;;;GAKG;AACH,KAAK,UAAU,GAAG,cAAc,MAAM,CAAC,CAAC;AAExC;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,oBAAqB,YAAW,qBAAqB;IAChE,OAAO,CAAC,UAAU,CAA6D;IAC/E,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAc;IACrC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA4B;IACrD,OAAO,CAAC,iBAAiB,CAAoC;gBAEjD,MAAM,EAAE,WAAW,EAAE,QAAQ,CAAC,EAAE,MAAM,OAAO,CAAC,UAAU,CAAC;YAKvD,OAAO;YAOP,aAAa;IAQ3B;;;;;;;;;;;;;;;;;;;;OAoBG;IACG,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,OAAO,CAAC,0BAA0B,CAAC;CAkE3G"}
|
|
@@ -35,6 +35,24 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.TokenVerifierService = void 0;
|
|
37
37
|
const core_1 = require("@nauth-toolkit/core");
|
|
38
|
+
/**
|
|
39
|
+
* Token Verifier Service for Google OAuth (Platform-Agnostic)
|
|
40
|
+
*
|
|
41
|
+
* Handles secure verification of Google ID tokens using JWKS public keys.
|
|
42
|
+
* Uses cryptographic signature verification to ensure tokens are authentic.
|
|
43
|
+
*
|
|
44
|
+
* Security Features:
|
|
45
|
+
* - Google: Verifies JWT signature with Google's JWKS public keys using jwks-rsa
|
|
46
|
+
*
|
|
47
|
+
* This is a plain TypeScript class with no framework dependencies.
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* ```typescript
|
|
51
|
+
* const verifier = new TokenVerifierService(config);
|
|
52
|
+
* const profile = await verifier.verifyGoogleToken(idToken, clientId);
|
|
53
|
+
* console.log(profile.email); // Verified email from Google
|
|
54
|
+
* ```
|
|
55
|
+
*/
|
|
38
56
|
class TokenVerifierService {
|
|
39
57
|
googleJWKS = null;
|
|
40
58
|
logger;
|
|
@@ -54,15 +72,39 @@ class TokenVerifierService {
|
|
|
54
72
|
if (this.googleJWKS)
|
|
55
73
|
return this.googleJWKS;
|
|
56
74
|
const jose = await this.getJose();
|
|
75
|
+
// Initialize Google Remote JWKS (fetched and cached by jose)
|
|
57
76
|
this.googleJWKS = jose.createRemoteJWKSet(new URL('https://www.googleapis.com/oauth2/v3/certs'));
|
|
58
77
|
return this.googleJWKS;
|
|
59
78
|
}
|
|
79
|
+
/**
|
|
80
|
+
* Verify Google ID token with JWT signature validation
|
|
81
|
+
*
|
|
82
|
+
* Fetches Google's public keys from their JWKS endpoint and verifies the
|
|
83
|
+
* JWT signature to ensure authenticity.
|
|
84
|
+
*
|
|
85
|
+
* @param idToken - ID token from Google OAuth
|
|
86
|
+
* @param clientId - Google OAuth client ID for audience validation (supports multiple IDs)
|
|
87
|
+
* @returns Verified user profile data
|
|
88
|
+
* @throws {BadRequestException} When token is invalid, expired, or signature fails
|
|
89
|
+
*
|
|
90
|
+
* @example
|
|
91
|
+
* ```typescript
|
|
92
|
+
* try {
|
|
93
|
+
* const profile = await verifier.verifyGoogleToken(idToken, ['web-client-id', 'ios-client-id']);
|
|
94
|
+
* console.log(`Verified email: ${profile.email}`);
|
|
95
|
+
* } catch (error) {
|
|
96
|
+
* console.error('Token verification failed:', error.message);
|
|
97
|
+
* }
|
|
98
|
+
* ```
|
|
99
|
+
*/
|
|
60
100
|
async verifyGoogleToken(idToken, clientId) {
|
|
61
101
|
try {
|
|
62
102
|
const jose = await this.getJose();
|
|
63
103
|
const googleJWKS = await this.getGoogleJWKS();
|
|
104
|
+
// Support multiple client IDs (web, iOS, Android)
|
|
64
105
|
const clientIds = Array.isArray(clientId) ? clientId : [clientId];
|
|
65
106
|
this.logger?.debug?.(`[TokenVerifier] Verifying Google token with ${clientIds.length} accepted client ID(s)`);
|
|
107
|
+
// Verify token with jose using Google's JWKS; try each audience if multiple provided
|
|
66
108
|
let verified;
|
|
67
109
|
let lastError;
|
|
68
110
|
for (const aud of clientIds) {
|
|
@@ -70,7 +112,7 @@ class TokenVerifierService {
|
|
|
70
112
|
verified = await jose.jwtVerify(idToken, googleJWKS, {
|
|
71
113
|
issuer: 'https://accounts.google.com',
|
|
72
114
|
audience: aud,
|
|
73
|
-
clockTolerance: 300,
|
|
115
|
+
clockTolerance: 300, // 5 minutes leeway
|
|
74
116
|
});
|
|
75
117
|
break;
|
|
76
118
|
}
|
|
@@ -86,6 +128,7 @@ class TokenVerifierService {
|
|
|
86
128
|
if (!payload.email_verified) {
|
|
87
129
|
throw new core_1.NAuthException(core_1.AuthErrorCode.SOCIAL_EMAIL_REQUIRED, 'Google email not verified');
|
|
88
130
|
}
|
|
131
|
+
// Validate required fields (sub and email are required by JWT spec and Google tokens)
|
|
89
132
|
if (!payload.sub || !payload.email) {
|
|
90
133
|
throw new core_1.NAuthException(core_1.AuthErrorCode.SOCIAL_TOKEN_INVALID, 'Missing required fields in Google token (sub or email)');
|
|
91
134
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"token-verifier.service.js","sourceRoot":"","sources":["../../src/token-verifier.service.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AACA,8CAAqH;
|
|
1
|
+
{"version":3,"file":"token-verifier.service.js","sourceRoot":"","sources":["../../src/token-verifier.service.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,9 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Verified Token Profile - Google OAuth
|
|
3
|
+
*
|
|
4
|
+
* Standardized return type for Google token verification.
|
|
5
|
+
* This is provider-specific and should not be in core.
|
|
6
|
+
*/
|
|
1
7
|
export interface VerifiedGoogleTokenProfile {
|
|
8
|
+
/**
|
|
9
|
+
* Google user ID (sub claim)
|
|
10
|
+
*/
|
|
2
11
|
sub: string;
|
|
12
|
+
/**
|
|
13
|
+
* User's email address
|
|
14
|
+
*/
|
|
3
15
|
email: string;
|
|
16
|
+
/**
|
|
17
|
+
* Whether the email is verified by Google
|
|
18
|
+
*/
|
|
4
19
|
email_verified: boolean;
|
|
20
|
+
/**
|
|
21
|
+
* User's first name (given name)
|
|
22
|
+
*/
|
|
5
23
|
given_name?: string;
|
|
24
|
+
/**
|
|
25
|
+
* User's last name (family name)
|
|
26
|
+
*/
|
|
6
27
|
family_name?: string;
|
|
28
|
+
/**
|
|
29
|
+
* User's profile picture URL
|
|
30
|
+
*/
|
|
7
31
|
picture?: string;
|
|
8
32
|
}
|
|
9
33
|
//# sourceMappingURL=verified-token-profile.interface.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"verified-token-profile.interface.d.ts","sourceRoot":"","sources":["../../src/verified-token-profile.interface.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"verified-token-profile.interface.d.ts","sourceRoot":"","sources":["../../src/verified-token-profile.interface.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,WAAW,0BAA0B;IACzC;;OAEG;IACH,GAAG,EAAE,MAAM,CAAC;IAEZ;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IAEd;;OAEG;IACH,cAAc,EAAE,OAAO,CAAC;IAExB;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB"}
|