@acmekit/auth-google 2.13.1

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/README.md ADDED
@@ -0,0 +1,11 @@
1
+ ## Testing
2
+
3
+ In order to manually test the flow, you can do the following:
4
+
5
+ 1. Register an app in `https://console.cloud.google.com/apis/credentials/consent`
6
+ 2. Generate clientId and clientSecret credentials in the console
7
+ 3. Replace the values in the test with your credentials
8
+ 4. Remove the `server.listen()` call
9
+ 5. Run the tests, get the `location` value from the `authenticate` test, open the browser
10
+ 6. Once redirected, copy the `code` param from the URL, and add it in one of the `callback` success tests
11
+ 7. Once you run the tests, you should get back an access token, id token, and so on.
@@ -0,0 +1,3 @@
1
+ declare const _default: import("@acmekit/types").ModuleProviderExports;
2
+ export default _default;
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAKA,wBAEE"}
package/dist/index.js ADDED
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const utils_1 = require("@acmekit/framework/utils");
4
+ const google_1 = require("./services/google");
5
+ const services = [google_1.GoogleAuthService];
6
+ exports.default = (0, utils_1.ModuleProvider)(utils_1.Modules.AUTH, {
7
+ services,
8
+ });
9
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;AAAA,oDAAkE;AAClE,8CAAqD;AAErD,MAAM,QAAQ,GAAG,CAAC,0BAAiB,CAAC,CAAA;AAEpC,kBAAe,IAAA,sBAAc,EAAC,eAAO,CAAC,IAAI,EAAE;IAC1C,QAAQ;CACT,CAAC,CAAA"}
@@ -0,0 +1,30 @@
1
+ import { AuthenticationInput, AuthenticationResponse, AuthIdentityProviderService, GoogleAuthProviderOptions, Logger } from "@acmekit/framework/types";
2
+ import { AbstractAuthModuleProvider } from "@acmekit/framework/utils";
3
+ type InjectedDependencies = {
4
+ logger: Logger;
5
+ };
6
+ interface LocalServiceConfig extends GoogleAuthProviderOptions {
7
+ }
8
+ export declare class GoogleAuthService extends AbstractAuthModuleProvider {
9
+ static identifier: string;
10
+ static DISPLAY_NAME: string;
11
+ protected config_: LocalServiceConfig;
12
+ protected logger_: Logger;
13
+ static validateOptions(options: GoogleAuthProviderOptions): void;
14
+ constructor({ logger }: InjectedDependencies, options: GoogleAuthProviderOptions);
15
+ register(_: any): Promise<AuthenticationResponse>;
16
+ authenticate(req: AuthenticationInput, authIdentityService: AuthIdentityProviderService): Promise<AuthenticationResponse>;
17
+ validateCallback(req: AuthenticationInput, authIdentityService: AuthIdentityProviderService): Promise<AuthenticationResponse>;
18
+ verify_(idToken: string | undefined, authIdentityService: AuthIdentityProviderService): Promise<{
19
+ success: boolean;
20
+ error: any;
21
+ authIdentity?: undefined;
22
+ } | {
23
+ success: boolean;
24
+ authIdentity: any;
25
+ error?: undefined;
26
+ }>;
27
+ private getRedirect;
28
+ }
29
+ export {};
30
+ //# sourceMappingURL=google.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"google.d.ts","sourceRoot":"","sources":["../../src/services/google.ts"],"names":[],"mappings":"AACA,OAAO,EACL,mBAAmB,EACnB,sBAAsB,EACtB,2BAA2B,EAC3B,yBAAyB,EACzB,MAAM,EACP,MAAM,0BAA0B,CAAA;AACjC,OAAO,EACL,0BAA0B,EAE3B,MAAM,0BAA0B,CAAA;AAGjC,KAAK,oBAAoB,GAAG;IAC1B,MAAM,EAAE,MAAM,CAAA;CACf,CAAA;AAED,UAAU,kBAAmB,SAAQ,yBAAyB;CAAG;AACjE,qBAAa,iBAAkB,SAAQ,0BAA0B;IAC/D,MAAM,CAAC,UAAU,SAAW;IAC5B,MAAM,CAAC,YAAY,SAA0B;IAE7C,SAAS,CAAC,OAAO,EAAE,kBAAkB,CAAA;IACrC,SAAS,CAAC,OAAO,EAAE,MAAM,CAAA;IAEzB,MAAM,CAAC,eAAe,CAAC,OAAO,EAAE,yBAAyB;gBAevD,EAAE,MAAM,EAAE,EAAE,oBAAoB,EAChC,OAAO,EAAE,yBAAyB;IAQ9B,QAAQ,CAAC,CAAC,KAAA,GAAG,OAAO,CAAC,sBAAsB,CAAC;IAO5C,YAAY,CAChB,GAAG,EAAE,mBAAmB,EACxB,mBAAmB,EAAE,2BAA2B,GAC/C,OAAO,CAAC,sBAAsB,CAAC;IAoB5B,gBAAgB,CACpB,GAAG,EAAE,mBAAmB,EACxB,mBAAmB,EAAE,2BAA2B,GAC/C,OAAO,CAAC,sBAAsB,CAAC;IAsD5B,OAAO,CACX,OAAO,EAAE,MAAM,GAAG,SAAS,EAC3B,mBAAmB,EAAE,2BAA2B;;;;;;;;;IAmDlD,OAAO,CAAC,WAAW;CAUpB"}
@@ -0,0 +1,140 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.GoogleAuthService = void 0;
7
+ const crypto_1 = __importDefault(require("crypto"));
8
+ const utils_1 = require("@acmekit/framework/utils");
9
+ const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
10
+ class GoogleAuthService extends utils_1.AbstractAuthModuleProvider {
11
+ static validateOptions(options) {
12
+ if (!options.clientId) {
13
+ throw new Error("Google clientId is required");
14
+ }
15
+ if (!options.clientSecret) {
16
+ throw new Error("Google clientSecret is required");
17
+ }
18
+ if (!options.callbackUrl) {
19
+ throw new Error("Google callbackUrl is required");
20
+ }
21
+ }
22
+ constructor({ logger }, options) {
23
+ // @ts-ignore
24
+ super(...arguments);
25
+ this.config_ = options;
26
+ this.logger_ = logger;
27
+ }
28
+ async register(_) {
29
+ throw new utils_1.AcmeKitError(utils_1.AcmeKitError.Types.NOT_ALLOWED, "Google does not support registration. Use method `authenticate` instead.");
30
+ }
31
+ async authenticate(req, authIdentityService) {
32
+ const query = req.query ?? {};
33
+ const body = req.body ?? {};
34
+ if (query.error) {
35
+ return {
36
+ success: false,
37
+ error: `${query.error_description}, read more at: ${query.error_uri}`,
38
+ };
39
+ }
40
+ const stateKey = crypto_1.default.randomBytes(32).toString("hex");
41
+ const state = {
42
+ callback_url: body?.callback_url ?? this.config_.callbackUrl,
43
+ };
44
+ await authIdentityService.setState(stateKey, state);
45
+ return this.getRedirect(this.config_.clientId, state.callback_url, stateKey);
46
+ }
47
+ async validateCallback(req, authIdentityService) {
48
+ const query = req.query ?? {};
49
+ const body = req.body ?? {};
50
+ if (query.error) {
51
+ return {
52
+ success: false,
53
+ error: `${query.error_description}, read more at: ${query.error_uri}`,
54
+ };
55
+ }
56
+ const code = query?.code ?? body?.code;
57
+ if (!code) {
58
+ return { success: false, error: "No code provided" };
59
+ }
60
+ const state = await authIdentityService.getState(query?.state);
61
+ if (!state) {
62
+ return { success: false, error: "No state provided, or session expired" };
63
+ }
64
+ const params = `client_id=${this.config_.clientId}&client_secret=${this.config_.clientSecret}&code=${code}&redirect_uri=${state.callback_url}&grant_type=authorization_code`;
65
+ const exchangeTokenUrl = new URL(`https://oauth2.googleapis.com/token?${params}`);
66
+ try {
67
+ const response = await fetch(exchangeTokenUrl.toString(), {
68
+ method: "POST",
69
+ }).then((r) => {
70
+ if (!r.ok) {
71
+ throw new utils_1.AcmeKitError(utils_1.AcmeKitError.Types.INVALID_DATA, `Could not exchange token, ${r.status}, ${r.statusText}`);
72
+ }
73
+ return r.json();
74
+ });
75
+ const { authIdentity, success } = await this.verify_(response.id_token, authIdentityService);
76
+ return {
77
+ success,
78
+ authIdentity,
79
+ };
80
+ }
81
+ catch (error) {
82
+ return { success: false, error: error.message };
83
+ }
84
+ }
85
+ async verify_(idToken, authIdentityService) {
86
+ if (!idToken) {
87
+ return { success: false, error: "No ID found" };
88
+ }
89
+ const jwtData = jsonwebtoken_1.default.decode(idToken, {
90
+ complete: true,
91
+ });
92
+ const payload = jwtData.payload;
93
+ if (!payload.email_verified) {
94
+ throw new utils_1.AcmeKitError(utils_1.AcmeKitError.Types.INVALID_DATA, "Email not verified, cannot proceed with authentication");
95
+ }
96
+ const entity_id = payload.sub;
97
+ const userMetadata = {
98
+ name: payload.name,
99
+ email: payload.email,
100
+ picture: payload.picture,
101
+ given_name: payload.given_name,
102
+ family_name: payload.family_name,
103
+ };
104
+ let authIdentity;
105
+ try {
106
+ authIdentity = await authIdentityService.retrieve({
107
+ entity_id,
108
+ });
109
+ }
110
+ catch (error) {
111
+ if (error.type === utils_1.AcmeKitError.Types.NOT_FOUND) {
112
+ const createdAuthIdentity = await authIdentityService.create({
113
+ entity_id,
114
+ user_metadata: userMetadata,
115
+ });
116
+ authIdentity = createdAuthIdentity;
117
+ }
118
+ else {
119
+ return { success: false, error: error.message };
120
+ }
121
+ }
122
+ return {
123
+ success: true,
124
+ authIdentity,
125
+ };
126
+ }
127
+ getRedirect(clientId, callbackUrl, stateKey) {
128
+ const authUrl = new URL(`https://accounts.google.com/o/oauth2/v2/auth`);
129
+ authUrl.searchParams.set("redirect_uri", callbackUrl);
130
+ authUrl.searchParams.set("client_id", clientId);
131
+ authUrl.searchParams.set("response_type", "code");
132
+ authUrl.searchParams.set("scope", "email profile openid");
133
+ authUrl.searchParams.set("state", stateKey);
134
+ return { success: true, location: authUrl.toString() };
135
+ }
136
+ }
137
+ exports.GoogleAuthService = GoogleAuthService;
138
+ GoogleAuthService.identifier = "google";
139
+ GoogleAuthService.DISPLAY_NAME = "Google Authentication";
140
+ //# sourceMappingURL=google.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"google.js","sourceRoot":"","sources":["../../src/services/google.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ {"root":["../src/index.ts","../src/services/google.ts"],"version":"5.9.3"}
package/package.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "@acmekit/auth-google",
3
+ "version": "2.13.1",
4
+ "description": "Google OAuth authentication provider for AcmeKit",
5
+ "main": "dist/index.js",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/acmekit/acmekit",
9
+ "directory": "packages/modules/providers/auth-google"
10
+ },
11
+ "files": [
12
+ "dist",
13
+ "!dist/**/__tests__",
14
+ "!dist/**/__mocks__",
15
+ "!dist/**/__fixtures__"
16
+ ],
17
+ "engines": {
18
+ "node": ">=20"
19
+ },
20
+ "author": "AcmeKit",
21
+ "license": "MIT",
22
+ "scripts": {
23
+ "test": "../../../../node_modules/.bin/jest --passWithNoTests src",
24
+ "test:integration": "../../../../node_modules/.bin/jest --passWithNoTests --forceExit --testPathPattern=\"integration-tests/__tests__/.*\\.spec\\.ts\"",
25
+ "build": "yarn run -T rimraf dist && yarn run -T tsc --build",
26
+ "watch": "yarn run -T tsc --watch"
27
+ },
28
+ "devDependencies": {
29
+ "@acmekit/framework": "2.13.1"
30
+ },
31
+ "dependencies": {
32
+ "jsonwebtoken": "^9.0.2"
33
+ },
34
+ "peerDependencies": {
35
+ "@acmekit/framework": "2.13.1"
36
+ },
37
+ "keywords": [
38
+ "acmekit-provider",
39
+ "acmekit-provider-auth-google"
40
+ ]
41
+ }