@ainetwork/adk-provider-auth-m365 0.3.0

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.
@@ -0,0 +1,119 @@
1
+ // implements/m365.auth.ts
2
+ import { BaseAuth } from "@ainetwork/adk/modules";
3
+ import jwt from "jsonwebtoken";
4
+ import jwksClient from "jwks-rsa";
5
+ var M365Auth = class extends BaseAuth {
6
+ constructor(config) {
7
+ super();
8
+ this.config = config;
9
+ this.cloudInstance = this.config.cloudInstance || "https://login.microsoftonline.com";
10
+ this.expectedIssuer = `${this.cloudInstance}/${this.config.tenantId}/v2.0`;
11
+ this.jwksClient = jwksClient({
12
+ jwksUri: `${this.cloudInstance}/${this.config.tenantId}/discovery/v2.0/keys`,
13
+ cache: true,
14
+ cacheMaxAge: 864e5,
15
+ // 24 hours
16
+ rateLimit: true,
17
+ jwksRequestsPerMinute: 10
18
+ });
19
+ }
20
+ jwksClient;
21
+ cloudInstance;
22
+ expectedIssuer;
23
+ getSigningKey = (header, callback) => {
24
+ this.jwksClient.getSigningKey(header.kid, (err, key) => {
25
+ if (err) {
26
+ callback(err);
27
+ return;
28
+ }
29
+ const signingKey = key?.getPublicKey();
30
+ callback(null, signingKey);
31
+ });
32
+ };
33
+ verifyAzureADToken(token) {
34
+ return new Promise((resolve, reject) => {
35
+ jwt.verify(
36
+ token,
37
+ this.getSigningKey,
38
+ {
39
+ algorithms: ["RS256"],
40
+ audience: this.config.clientId,
41
+ issuer: this.expectedIssuer
42
+ },
43
+ (err, decoded) => {
44
+ if (err) {
45
+ reject(err);
46
+ return;
47
+ }
48
+ resolve(decoded);
49
+ }
50
+ );
51
+ });
52
+ }
53
+ verifyNextAuthToken(token) {
54
+ return new Promise((resolve, reject) => {
55
+ if (!this.config.nextAuthSecret) {
56
+ reject(new Error("NextAuth secret is required for NextAuth token verification"));
57
+ return;
58
+ }
59
+ jwt.verify(
60
+ token,
61
+ this.config.nextAuthSecret,
62
+ {
63
+ algorithms: ["HS256"]
64
+ },
65
+ (err, decoded) => {
66
+ if (err) {
67
+ reject(err);
68
+ return;
69
+ }
70
+ resolve(decoded);
71
+ }
72
+ );
73
+ });
74
+ }
75
+ async authenticate(req, res) {
76
+ const token = this.extractBearerToken(req);
77
+ if (!token) {
78
+ return { isAuthenticated: false };
79
+ }
80
+ try {
81
+ if (this.config.nextAuthSecret) {
82
+ try {
83
+ const payload2 = await this.verifyNextAuthToken(token);
84
+ if (payload2.sub) {
85
+ return {
86
+ isAuthenticated: true,
87
+ userId: payload2.sub
88
+ };
89
+ }
90
+ } catch {
91
+ }
92
+ }
93
+ const payload = await this.verifyAzureADToken(token);
94
+ if (!payload.oid && !payload.sub) {
95
+ console.error("M365 auth verification failed: Token does not contain oid or sub claim");
96
+ return { isAuthenticated: false };
97
+ }
98
+ return {
99
+ isAuthenticated: true,
100
+ userId: payload.oid || payload.sub
101
+ };
102
+ } catch (err) {
103
+ console.error("M365 auth verification failed:", err.message);
104
+ return { isAuthenticated: false };
105
+ }
106
+ }
107
+ extractBearerToken(req) {
108
+ const authHeader = req.headers.authorization;
109
+ if (!authHeader?.startsWith("Bearer ")) {
110
+ return null;
111
+ }
112
+ return authHeader.substring(7);
113
+ }
114
+ };
115
+
116
+ export {
117
+ M365Auth
118
+ };
119
+ //# sourceMappingURL=chunk-D55IH5LY.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../implements/m365.auth.ts"],"sourcesContent":["import { BaseAuth } from \"@ainetwork/adk/modules\";\nimport { AuthResponse } from \"@ainetwork/adk/types/auth\";\nimport type { Request } from \"express\";\nimport jwt, { JwtHeader, SigningKeyCallback } from \"jsonwebtoken\";\nimport jwksClient from \"jwks-rsa\";\n\nexport interface M365AuthConfig {\n clientId: string;\n tenantId: string;\n cloudInstance?: string;\n nextAuthSecret?: string;\n}\n\ninterface AzureADTokenPayload {\n aud: string;\n iss: string;\n iat: number;\n nbf: number;\n exp: number;\n oid?: string;\n sub?: string;\n tid?: string;\n preferred_username?: string;\n email?: string;\n name?: string;\n}\n\ninterface NextAuthJWTPayload {\n name?: string;\n email?: string;\n picture?: string;\n sub: string;\n iat: number;\n exp: number;\n jti?: string;\n}\n\nexport class M365Auth extends BaseAuth {\n private readonly jwksClient: jwksClient.JwksClient;\n private readonly cloudInstance: string;\n private readonly expectedIssuer: string;\n\n constructor(private readonly config: M365AuthConfig) {\n super();\n this.cloudInstance = this.config.cloudInstance || \"https://login.microsoftonline.com\";\n this.expectedIssuer = `${this.cloudInstance}/${this.config.tenantId}/v2.0`;\n\n this.jwksClient = jwksClient({\n jwksUri: `${this.cloudInstance}/${this.config.tenantId}/discovery/v2.0/keys`,\n cache: true,\n cacheMaxAge: 86400000, // 24 hours\n rateLimit: true,\n jwksRequestsPerMinute: 10,\n });\n }\n\n private getSigningKey = (header: JwtHeader, callback: SigningKeyCallback): void => {\n this.jwksClient.getSigningKey(header.kid, (err, key) => {\n if (err) {\n callback(err);\n return;\n }\n const signingKey = key?.getPublicKey();\n callback(null, signingKey);\n });\n };\n\n private verifyAzureADToken(token: string): Promise<AzureADTokenPayload> {\n return new Promise((resolve, reject) => {\n jwt.verify(\n token,\n this.getSigningKey,\n {\n algorithms: [\"RS256\"],\n audience: this.config.clientId,\n issuer: this.expectedIssuer,\n },\n (err: Error | null, decoded: unknown) => {\n if (err) {\n reject(err);\n return;\n }\n resolve(decoded as AzureADTokenPayload);\n }\n );\n });\n }\n\n private verifyNextAuthToken(token: string): Promise<NextAuthJWTPayload> {\n return new Promise((resolve, reject) => {\n if (!this.config.nextAuthSecret) {\n reject(new Error(\"NextAuth secret is required for NextAuth token verification\"));\n return;\n }\n\n jwt.verify(\n token,\n this.config.nextAuthSecret,\n {\n algorithms: [\"HS256\"],\n },\n (err: Error | null, decoded: unknown) => {\n if (err) {\n reject(err);\n return;\n }\n resolve(decoded as NextAuthJWTPayload);\n }\n );\n });\n }\n\n public async authenticate(req: any, res: any): Promise<AuthResponse> {\n const token = this.extractBearerToken(req);\n if (!token) {\n return { isAuthenticated: false };\n }\n\n try {\n // First, try to verify as NextAuth JWT token (signed with NEXTAUTH_SECRET)\n if (this.config.nextAuthSecret) {\n try {\n const payload = await this.verifyNextAuthToken(token);\n if (payload.sub) {\n return {\n isAuthenticated: true,\n userId: payload.sub,\n };\n }\n } catch {\n // If NextAuth verification fails, try Azure AD token verification\n }\n }\n\n // Try to verify as Azure AD token\n const payload = await this.verifyAzureADToken(token);\n\n if (!payload.oid && !payload.sub) {\n console.error(\"M365 auth verification failed: Token does not contain oid or sub claim\");\n return { isAuthenticated: false };\n }\n\n return {\n isAuthenticated: true,\n userId: (payload.oid || payload.sub) as string,\n };\n } catch (err) {\n console.error(\"M365 auth verification failed:\", (err as Error).message);\n return { isAuthenticated: false };\n }\n }\n\n private extractBearerToken(req: Request): string | null {\n const authHeader = req.headers.authorization;\n if (!authHeader?.startsWith(\"Bearer \")) {\n return null;\n }\n return authHeader.substring(7);\n }\n}\n"],"mappings":"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","names":["payload"]}
@@ -0,0 +1,153 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // implements/m365.auth.ts
31
+ var m365_auth_exports = {};
32
+ __export(m365_auth_exports, {
33
+ M365Auth: () => M365Auth
34
+ });
35
+ module.exports = __toCommonJS(m365_auth_exports);
36
+ var import_modules = require("@ainetwork/adk/modules");
37
+ var import_jsonwebtoken = __toESM(require("jsonwebtoken"), 1);
38
+ var import_jwks_rsa = __toESM(require("jwks-rsa"), 1);
39
+ var M365Auth = class extends import_modules.BaseAuth {
40
+ constructor(config) {
41
+ super();
42
+ this.config = config;
43
+ this.cloudInstance = this.config.cloudInstance || "https://login.microsoftonline.com";
44
+ this.expectedIssuer = `${this.cloudInstance}/${this.config.tenantId}/v2.0`;
45
+ this.jwksClient = (0, import_jwks_rsa.default)({
46
+ jwksUri: `${this.cloudInstance}/${this.config.tenantId}/discovery/v2.0/keys`,
47
+ cache: true,
48
+ cacheMaxAge: 864e5,
49
+ // 24 hours
50
+ rateLimit: true,
51
+ jwksRequestsPerMinute: 10
52
+ });
53
+ }
54
+ jwksClient;
55
+ cloudInstance;
56
+ expectedIssuer;
57
+ getSigningKey = (header, callback) => {
58
+ this.jwksClient.getSigningKey(header.kid, (err, key) => {
59
+ if (err) {
60
+ callback(err);
61
+ return;
62
+ }
63
+ const signingKey = key?.getPublicKey();
64
+ callback(null, signingKey);
65
+ });
66
+ };
67
+ verifyAzureADToken(token) {
68
+ return new Promise((resolve, reject) => {
69
+ import_jsonwebtoken.default.verify(
70
+ token,
71
+ this.getSigningKey,
72
+ {
73
+ algorithms: ["RS256"],
74
+ audience: this.config.clientId,
75
+ issuer: this.expectedIssuer
76
+ },
77
+ (err, decoded) => {
78
+ if (err) {
79
+ reject(err);
80
+ return;
81
+ }
82
+ resolve(decoded);
83
+ }
84
+ );
85
+ });
86
+ }
87
+ verifyNextAuthToken(token) {
88
+ return new Promise((resolve, reject) => {
89
+ if (!this.config.nextAuthSecret) {
90
+ reject(new Error("NextAuth secret is required for NextAuth token verification"));
91
+ return;
92
+ }
93
+ import_jsonwebtoken.default.verify(
94
+ token,
95
+ this.config.nextAuthSecret,
96
+ {
97
+ algorithms: ["HS256"]
98
+ },
99
+ (err, decoded) => {
100
+ if (err) {
101
+ reject(err);
102
+ return;
103
+ }
104
+ resolve(decoded);
105
+ }
106
+ );
107
+ });
108
+ }
109
+ async authenticate(req, res) {
110
+ const token = this.extractBearerToken(req);
111
+ if (!token) {
112
+ return { isAuthenticated: false };
113
+ }
114
+ try {
115
+ if (this.config.nextAuthSecret) {
116
+ try {
117
+ const payload2 = await this.verifyNextAuthToken(token);
118
+ if (payload2.sub) {
119
+ return {
120
+ isAuthenticated: true,
121
+ userId: payload2.sub
122
+ };
123
+ }
124
+ } catch {
125
+ }
126
+ }
127
+ const payload = await this.verifyAzureADToken(token);
128
+ if (!payload.oid && !payload.sub) {
129
+ console.error("M365 auth verification failed: Token does not contain oid or sub claim");
130
+ return { isAuthenticated: false };
131
+ }
132
+ return {
133
+ isAuthenticated: true,
134
+ userId: payload.oid || payload.sub
135
+ };
136
+ } catch (err) {
137
+ console.error("M365 auth verification failed:", err.message);
138
+ return { isAuthenticated: false };
139
+ }
140
+ }
141
+ extractBearerToken(req) {
142
+ const authHeader = req.headers.authorization;
143
+ if (!authHeader?.startsWith("Bearer ")) {
144
+ return null;
145
+ }
146
+ return authHeader.substring(7);
147
+ }
148
+ };
149
+ // Annotate the CommonJS export names for ESM import in node:
150
+ 0 && (module.exports = {
151
+ M365Auth
152
+ });
153
+ //# sourceMappingURL=m365.auth.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../implements/m365.auth.ts"],"sourcesContent":["import { BaseAuth } from \"@ainetwork/adk/modules\";\nimport { AuthResponse } from \"@ainetwork/adk/types/auth\";\nimport type { Request } from \"express\";\nimport jwt, { JwtHeader, SigningKeyCallback } from \"jsonwebtoken\";\nimport jwksClient from \"jwks-rsa\";\n\nexport interface M365AuthConfig {\n clientId: string;\n tenantId: string;\n cloudInstance?: string;\n nextAuthSecret?: string;\n}\n\ninterface AzureADTokenPayload {\n aud: string;\n iss: string;\n iat: number;\n nbf: number;\n exp: number;\n oid?: string;\n sub?: string;\n tid?: string;\n preferred_username?: string;\n email?: string;\n name?: string;\n}\n\ninterface NextAuthJWTPayload {\n name?: string;\n email?: string;\n picture?: string;\n sub: string;\n iat: number;\n exp: number;\n jti?: string;\n}\n\nexport class M365Auth extends BaseAuth {\n private readonly jwksClient: jwksClient.JwksClient;\n private readonly cloudInstance: string;\n private readonly expectedIssuer: string;\n\n constructor(private readonly config: M365AuthConfig) {\n super();\n this.cloudInstance = this.config.cloudInstance || \"https://login.microsoftonline.com\";\n this.expectedIssuer = `${this.cloudInstance}/${this.config.tenantId}/v2.0`;\n\n this.jwksClient = jwksClient({\n jwksUri: `${this.cloudInstance}/${this.config.tenantId}/discovery/v2.0/keys`,\n cache: true,\n cacheMaxAge: 86400000, // 24 hours\n rateLimit: true,\n jwksRequestsPerMinute: 10,\n });\n }\n\n private getSigningKey = (header: JwtHeader, callback: SigningKeyCallback): void => {\n this.jwksClient.getSigningKey(header.kid, (err, key) => {\n if (err) {\n callback(err);\n return;\n }\n const signingKey = key?.getPublicKey();\n callback(null, signingKey);\n });\n };\n\n private verifyAzureADToken(token: string): Promise<AzureADTokenPayload> {\n return new Promise((resolve, reject) => {\n jwt.verify(\n token,\n this.getSigningKey,\n {\n algorithms: [\"RS256\"],\n audience: this.config.clientId,\n issuer: this.expectedIssuer,\n },\n (err: Error | null, decoded: unknown) => {\n if (err) {\n reject(err);\n return;\n }\n resolve(decoded as AzureADTokenPayload);\n }\n );\n });\n }\n\n private verifyNextAuthToken(token: string): Promise<NextAuthJWTPayload> {\n return new Promise((resolve, reject) => {\n if (!this.config.nextAuthSecret) {\n reject(new Error(\"NextAuth secret is required for NextAuth token verification\"));\n return;\n }\n\n jwt.verify(\n token,\n this.config.nextAuthSecret,\n {\n algorithms: [\"HS256\"],\n },\n (err: Error | null, decoded: unknown) => {\n if (err) {\n reject(err);\n return;\n }\n resolve(decoded as NextAuthJWTPayload);\n }\n );\n });\n }\n\n public async authenticate(req: any, res: any): Promise<AuthResponse> {\n const token = this.extractBearerToken(req);\n if (!token) {\n return { isAuthenticated: false };\n }\n\n try {\n // First, try to verify as NextAuth JWT token (signed with NEXTAUTH_SECRET)\n if (this.config.nextAuthSecret) {\n try {\n const payload = await this.verifyNextAuthToken(token);\n if (payload.sub) {\n return {\n isAuthenticated: true,\n userId: payload.sub,\n };\n }\n } catch {\n // If NextAuth verification fails, try Azure AD token verification\n }\n }\n\n // Try to verify as Azure AD token\n const payload = await this.verifyAzureADToken(token);\n\n if (!payload.oid && !payload.sub) {\n console.error(\"M365 auth verification failed: Token does not contain oid or sub claim\");\n return { isAuthenticated: false };\n }\n\n return {\n isAuthenticated: true,\n userId: (payload.oid || payload.sub) as string,\n };\n } catch (err) {\n console.error(\"M365 auth verification failed:\", (err as Error).message);\n return { isAuthenticated: false };\n }\n }\n\n private extractBearerToken(req: Request): string | null {\n const authHeader = req.headers.authorization;\n if (!authHeader?.startsWith(\"Bearer \")) {\n return null;\n }\n return authHeader.substring(7);\n }\n}\n"],"mappings":"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","names":["jwksClient","jwt","payload"]}
@@ -0,0 +1,23 @@
1
+ import { BaseAuth } from '@ainetwork/adk/modules';
2
+ import { AuthResponse } from '@ainetwork/adk/types/auth';
3
+
4
+ interface M365AuthConfig {
5
+ clientId: string;
6
+ tenantId: string;
7
+ cloudInstance?: string;
8
+ nextAuthSecret?: string;
9
+ }
10
+ declare class M365Auth extends BaseAuth {
11
+ private readonly config;
12
+ private readonly jwksClient;
13
+ private readonly cloudInstance;
14
+ private readonly expectedIssuer;
15
+ constructor(config: M365AuthConfig);
16
+ private getSigningKey;
17
+ private verifyAzureADToken;
18
+ private verifyNextAuthToken;
19
+ authenticate(req: any, res: any): Promise<AuthResponse>;
20
+ private extractBearerToken;
21
+ }
22
+
23
+ export { M365Auth, type M365AuthConfig };
@@ -0,0 +1,23 @@
1
+ import { BaseAuth } from '@ainetwork/adk/modules';
2
+ import { AuthResponse } from '@ainetwork/adk/types/auth';
3
+
4
+ interface M365AuthConfig {
5
+ clientId: string;
6
+ tenantId: string;
7
+ cloudInstance?: string;
8
+ nextAuthSecret?: string;
9
+ }
10
+ declare class M365Auth extends BaseAuth {
11
+ private readonly config;
12
+ private readonly jwksClient;
13
+ private readonly cloudInstance;
14
+ private readonly expectedIssuer;
15
+ constructor(config: M365AuthConfig);
16
+ private getSigningKey;
17
+ private verifyAzureADToken;
18
+ private verifyNextAuthToken;
19
+ authenticate(req: any, res: any): Promise<AuthResponse>;
20
+ private extractBearerToken;
21
+ }
22
+
23
+ export { M365Auth, type M365AuthConfig };
@@ -0,0 +1,7 @@
1
+ import {
2
+ M365Auth
3
+ } from "../chunk-D55IH5LY.js";
4
+ export {
5
+ M365Auth
6
+ };
7
+ //# sourceMappingURL=m365.auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
package/dist/index.cjs ADDED
@@ -0,0 +1,155 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // index.ts
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ M365Auth: () => M365Auth
34
+ });
35
+ module.exports = __toCommonJS(index_exports);
36
+
37
+ // implements/m365.auth.ts
38
+ var import_modules = require("@ainetwork/adk/modules");
39
+ var import_jsonwebtoken = __toESM(require("jsonwebtoken"), 1);
40
+ var import_jwks_rsa = __toESM(require("jwks-rsa"), 1);
41
+ var M365Auth = class extends import_modules.BaseAuth {
42
+ constructor(config) {
43
+ super();
44
+ this.config = config;
45
+ this.cloudInstance = this.config.cloudInstance || "https://login.microsoftonline.com";
46
+ this.expectedIssuer = `${this.cloudInstance}/${this.config.tenantId}/v2.0`;
47
+ this.jwksClient = (0, import_jwks_rsa.default)({
48
+ jwksUri: `${this.cloudInstance}/${this.config.tenantId}/discovery/v2.0/keys`,
49
+ cache: true,
50
+ cacheMaxAge: 864e5,
51
+ // 24 hours
52
+ rateLimit: true,
53
+ jwksRequestsPerMinute: 10
54
+ });
55
+ }
56
+ jwksClient;
57
+ cloudInstance;
58
+ expectedIssuer;
59
+ getSigningKey = (header, callback) => {
60
+ this.jwksClient.getSigningKey(header.kid, (err, key) => {
61
+ if (err) {
62
+ callback(err);
63
+ return;
64
+ }
65
+ const signingKey = key?.getPublicKey();
66
+ callback(null, signingKey);
67
+ });
68
+ };
69
+ verifyAzureADToken(token) {
70
+ return new Promise((resolve, reject) => {
71
+ import_jsonwebtoken.default.verify(
72
+ token,
73
+ this.getSigningKey,
74
+ {
75
+ algorithms: ["RS256"],
76
+ audience: this.config.clientId,
77
+ issuer: this.expectedIssuer
78
+ },
79
+ (err, decoded) => {
80
+ if (err) {
81
+ reject(err);
82
+ return;
83
+ }
84
+ resolve(decoded);
85
+ }
86
+ );
87
+ });
88
+ }
89
+ verifyNextAuthToken(token) {
90
+ return new Promise((resolve, reject) => {
91
+ if (!this.config.nextAuthSecret) {
92
+ reject(new Error("NextAuth secret is required for NextAuth token verification"));
93
+ return;
94
+ }
95
+ import_jsonwebtoken.default.verify(
96
+ token,
97
+ this.config.nextAuthSecret,
98
+ {
99
+ algorithms: ["HS256"]
100
+ },
101
+ (err, decoded) => {
102
+ if (err) {
103
+ reject(err);
104
+ return;
105
+ }
106
+ resolve(decoded);
107
+ }
108
+ );
109
+ });
110
+ }
111
+ async authenticate(req, res) {
112
+ const token = this.extractBearerToken(req);
113
+ if (!token) {
114
+ return { isAuthenticated: false };
115
+ }
116
+ try {
117
+ if (this.config.nextAuthSecret) {
118
+ try {
119
+ const payload2 = await this.verifyNextAuthToken(token);
120
+ if (payload2.sub) {
121
+ return {
122
+ isAuthenticated: true,
123
+ userId: payload2.sub
124
+ };
125
+ }
126
+ } catch {
127
+ }
128
+ }
129
+ const payload = await this.verifyAzureADToken(token);
130
+ if (!payload.oid && !payload.sub) {
131
+ console.error("M365 auth verification failed: Token does not contain oid or sub claim");
132
+ return { isAuthenticated: false };
133
+ }
134
+ return {
135
+ isAuthenticated: true,
136
+ userId: payload.oid || payload.sub
137
+ };
138
+ } catch (err) {
139
+ console.error("M365 auth verification failed:", err.message);
140
+ return { isAuthenticated: false };
141
+ }
142
+ }
143
+ extractBearerToken(req) {
144
+ const authHeader = req.headers.authorization;
145
+ if (!authHeader?.startsWith("Bearer ")) {
146
+ return null;
147
+ }
148
+ return authHeader.substring(7);
149
+ }
150
+ };
151
+ // Annotate the CommonJS export names for ESM import in node:
152
+ 0 && (module.exports = {
153
+ M365Auth
154
+ });
155
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../index.ts","../implements/m365.auth.ts"],"sourcesContent":["export { M365Auth, type M365AuthConfig } from \"./implements/m365.auth\";\n","import { BaseAuth } from \"@ainetwork/adk/modules\";\nimport { AuthResponse } from \"@ainetwork/adk/types/auth\";\nimport type { Request } from \"express\";\nimport jwt, { JwtHeader, SigningKeyCallback } from \"jsonwebtoken\";\nimport jwksClient from \"jwks-rsa\";\n\nexport interface M365AuthConfig {\n clientId: string;\n tenantId: string;\n cloudInstance?: string;\n nextAuthSecret?: string;\n}\n\ninterface AzureADTokenPayload {\n aud: string;\n iss: string;\n iat: number;\n nbf: number;\n exp: number;\n oid?: string;\n sub?: string;\n tid?: string;\n preferred_username?: string;\n email?: string;\n name?: string;\n}\n\ninterface NextAuthJWTPayload {\n name?: string;\n email?: string;\n picture?: string;\n sub: string;\n iat: number;\n exp: number;\n jti?: string;\n}\n\nexport class M365Auth extends BaseAuth {\n private readonly jwksClient: jwksClient.JwksClient;\n private readonly cloudInstance: string;\n private readonly expectedIssuer: string;\n\n constructor(private readonly config: M365AuthConfig) {\n super();\n this.cloudInstance = this.config.cloudInstance || \"https://login.microsoftonline.com\";\n this.expectedIssuer = `${this.cloudInstance}/${this.config.tenantId}/v2.0`;\n\n this.jwksClient = jwksClient({\n jwksUri: `${this.cloudInstance}/${this.config.tenantId}/discovery/v2.0/keys`,\n cache: true,\n cacheMaxAge: 86400000, // 24 hours\n rateLimit: true,\n jwksRequestsPerMinute: 10,\n });\n }\n\n private getSigningKey = (header: JwtHeader, callback: SigningKeyCallback): void => {\n this.jwksClient.getSigningKey(header.kid, (err, key) => {\n if (err) {\n callback(err);\n return;\n }\n const signingKey = key?.getPublicKey();\n callback(null, signingKey);\n });\n };\n\n private verifyAzureADToken(token: string): Promise<AzureADTokenPayload> {\n return new Promise((resolve, reject) => {\n jwt.verify(\n token,\n this.getSigningKey,\n {\n algorithms: [\"RS256\"],\n audience: this.config.clientId,\n issuer: this.expectedIssuer,\n },\n (err: Error | null, decoded: unknown) => {\n if (err) {\n reject(err);\n return;\n }\n resolve(decoded as AzureADTokenPayload);\n }\n );\n });\n }\n\n private verifyNextAuthToken(token: string): Promise<NextAuthJWTPayload> {\n return new Promise((resolve, reject) => {\n if (!this.config.nextAuthSecret) {\n reject(new Error(\"NextAuth secret is required for NextAuth token verification\"));\n return;\n }\n\n jwt.verify(\n token,\n this.config.nextAuthSecret,\n {\n algorithms: [\"HS256\"],\n },\n (err: Error | null, decoded: unknown) => {\n if (err) {\n reject(err);\n return;\n }\n resolve(decoded as NextAuthJWTPayload);\n }\n );\n });\n }\n\n public async authenticate(req: any, res: any): Promise<AuthResponse> {\n const token = this.extractBearerToken(req);\n if (!token) {\n return { isAuthenticated: false };\n }\n\n try {\n // First, try to verify as NextAuth JWT token (signed with NEXTAUTH_SECRET)\n if (this.config.nextAuthSecret) {\n try {\n const payload = await this.verifyNextAuthToken(token);\n if (payload.sub) {\n return {\n isAuthenticated: true,\n userId: payload.sub,\n };\n }\n } catch {\n // If NextAuth verification fails, try Azure AD token verification\n }\n }\n\n // Try to verify as Azure AD token\n const payload = await this.verifyAzureADToken(token);\n\n if (!payload.oid && !payload.sub) {\n console.error(\"M365 auth verification failed: Token does not contain oid or sub claim\");\n return { isAuthenticated: false };\n }\n\n return {\n isAuthenticated: true,\n userId: (payload.oid || payload.sub) as string,\n };\n } catch (err) {\n console.error(\"M365 auth verification failed:\", (err as Error).message);\n return { isAuthenticated: false };\n }\n }\n\n private extractBearerToken(req: Request): string | null {\n const authHeader = req.headers.authorization;\n if (!authHeader?.startsWith(\"Bearer \")) {\n return null;\n }\n return authHeader.substring(7);\n }\n}\n"],"mappings":"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","names":["jwksClient","jwt","payload"]}
@@ -0,0 +1,3 @@
1
+ export { M365Auth, M365AuthConfig } from './implements/m365.auth.cjs';
2
+ import '@ainetwork/adk/modules';
3
+ import '@ainetwork/adk/types/auth';
@@ -0,0 +1,3 @@
1
+ export { M365Auth, M365AuthConfig } from './implements/m365.auth.js';
2
+ import '@ainetwork/adk/modules';
3
+ import '@ainetwork/adk/types/auth';
package/dist/index.js ADDED
@@ -0,0 +1,7 @@
1
+ import {
2
+ M365Auth
3
+ } from "./chunk-D55IH5LY.js";
4
+ export {
5
+ M365Auth
6
+ };
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,160 @@
1
+ import { BaseAuth } from "@ainetwork/adk/modules";
2
+ import { AuthResponse } from "@ainetwork/adk/types/auth";
3
+ import type { Request } from "express";
4
+ import jwt, { JwtHeader, SigningKeyCallback } from "jsonwebtoken";
5
+ import jwksClient from "jwks-rsa";
6
+
7
+ export interface M365AuthConfig {
8
+ clientId: string;
9
+ tenantId: string;
10
+ cloudInstance?: string;
11
+ nextAuthSecret?: string;
12
+ }
13
+
14
+ interface AzureADTokenPayload {
15
+ aud: string;
16
+ iss: string;
17
+ iat: number;
18
+ nbf: number;
19
+ exp: number;
20
+ oid?: string;
21
+ sub?: string;
22
+ tid?: string;
23
+ preferred_username?: string;
24
+ email?: string;
25
+ name?: string;
26
+ }
27
+
28
+ interface NextAuthJWTPayload {
29
+ name?: string;
30
+ email?: string;
31
+ picture?: string;
32
+ sub: string;
33
+ iat: number;
34
+ exp: number;
35
+ jti?: string;
36
+ }
37
+
38
+ export class M365Auth extends BaseAuth {
39
+ private readonly jwksClient: jwksClient.JwksClient;
40
+ private readonly cloudInstance: string;
41
+ private readonly expectedIssuer: string;
42
+
43
+ constructor(private readonly config: M365AuthConfig) {
44
+ super();
45
+ this.cloudInstance = this.config.cloudInstance || "https://login.microsoftonline.com";
46
+ this.expectedIssuer = `${this.cloudInstance}/${this.config.tenantId}/v2.0`;
47
+
48
+ this.jwksClient = jwksClient({
49
+ jwksUri: `${this.cloudInstance}/${this.config.tenantId}/discovery/v2.0/keys`,
50
+ cache: true,
51
+ cacheMaxAge: 86400000, // 24 hours
52
+ rateLimit: true,
53
+ jwksRequestsPerMinute: 10,
54
+ });
55
+ }
56
+
57
+ private getSigningKey = (header: JwtHeader, callback: SigningKeyCallback): void => {
58
+ this.jwksClient.getSigningKey(header.kid, (err, key) => {
59
+ if (err) {
60
+ callback(err);
61
+ return;
62
+ }
63
+ const signingKey = key?.getPublicKey();
64
+ callback(null, signingKey);
65
+ });
66
+ };
67
+
68
+ private verifyAzureADToken(token: string): Promise<AzureADTokenPayload> {
69
+ return new Promise((resolve, reject) => {
70
+ jwt.verify(
71
+ token,
72
+ this.getSigningKey,
73
+ {
74
+ algorithms: ["RS256"],
75
+ audience: this.config.clientId,
76
+ issuer: this.expectedIssuer,
77
+ },
78
+ (err: Error | null, decoded: unknown) => {
79
+ if (err) {
80
+ reject(err);
81
+ return;
82
+ }
83
+ resolve(decoded as AzureADTokenPayload);
84
+ }
85
+ );
86
+ });
87
+ }
88
+
89
+ private verifyNextAuthToken(token: string): Promise<NextAuthJWTPayload> {
90
+ return new Promise((resolve, reject) => {
91
+ if (!this.config.nextAuthSecret) {
92
+ reject(new Error("NextAuth secret is required for NextAuth token verification"));
93
+ return;
94
+ }
95
+
96
+ jwt.verify(
97
+ token,
98
+ this.config.nextAuthSecret,
99
+ {
100
+ algorithms: ["HS256"],
101
+ },
102
+ (err: Error | null, decoded: unknown) => {
103
+ if (err) {
104
+ reject(err);
105
+ return;
106
+ }
107
+ resolve(decoded as NextAuthJWTPayload);
108
+ }
109
+ );
110
+ });
111
+ }
112
+
113
+ public async authenticate(req: any, res: any): Promise<AuthResponse> {
114
+ const token = this.extractBearerToken(req);
115
+ if (!token) {
116
+ return { isAuthenticated: false };
117
+ }
118
+
119
+ try {
120
+ // First, try to verify as NextAuth JWT token (signed with NEXTAUTH_SECRET)
121
+ if (this.config.nextAuthSecret) {
122
+ try {
123
+ const payload = await this.verifyNextAuthToken(token);
124
+ if (payload.sub) {
125
+ return {
126
+ isAuthenticated: true,
127
+ userId: payload.sub,
128
+ };
129
+ }
130
+ } catch {
131
+ // If NextAuth verification fails, try Azure AD token verification
132
+ }
133
+ }
134
+
135
+ // Try to verify as Azure AD token
136
+ const payload = await this.verifyAzureADToken(token);
137
+
138
+ if (!payload.oid && !payload.sub) {
139
+ console.error("M365 auth verification failed: Token does not contain oid or sub claim");
140
+ return { isAuthenticated: false };
141
+ }
142
+
143
+ return {
144
+ isAuthenticated: true,
145
+ userId: (payload.oid || payload.sub) as string,
146
+ };
147
+ } catch (err) {
148
+ console.error("M365 auth verification failed:", (err as Error).message);
149
+ return { isAuthenticated: false };
150
+ }
151
+ }
152
+
153
+ private extractBearerToken(req: Request): string | null {
154
+ const authHeader = req.headers.authorization;
155
+ if (!authHeader?.startsWith("Bearer ")) {
156
+ return null;
157
+ }
158
+ return authHeader.substring(7);
159
+ }
160
+ }
package/index.ts ADDED
@@ -0,0 +1 @@
1
+ export { M365Auth, type M365AuthConfig } from "./implements/m365.auth";
package/package.json ADDED
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "@ainetwork/adk-provider-auth-m365",
3
+ "version": "0.3.0",
4
+ "author": "AI Network (https://ainetwork.ai)",
5
+ "type": "module",
6
+ "engines": {
7
+ "node": ">=20"
8
+ },
9
+ "main": "./dist/index.cjs",
10
+ "module": "./dist/index.js",
11
+ "types": "./dist/index.d.ts",
12
+ "exports": {
13
+ ".": {
14
+ "types": "./dist/index.d.ts",
15
+ "import": "./dist/index.js",
16
+ "require": "./dist/index.cjs"
17
+ }
18
+ },
19
+ "scripts": {
20
+ "build": "tsup",
21
+ "clean": "rm -rf dist"
22
+ },
23
+ "dependencies": {
24
+ "@ainetwork/adk": "^0.3.0",
25
+ "jsonwebtoken": "^9.0.2",
26
+ "jwks-rsa": "^3.1.0"
27
+ },
28
+ "devDependencies": {
29
+ "@types/express": "^4.17.21",
30
+ "@types/jsonwebtoken": "^9.0.7",
31
+ "typescript": "^5.0.0"
32
+ },
33
+ "license": "MIT",
34
+ "publishConfig": {
35
+ "access": "public"
36
+ },
37
+ "gitHead": "741d325b4e2de45b8fe45e11d6a525d6467f5ab6"
38
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,9 @@
1
+ {
2
+ "extends": "../../../tsconfig.json",
3
+ "compilerOptions": {
4
+ "outDir": "./dist",
5
+ "rootDir": ".",
6
+ },
7
+ "include": ["index.ts", "implements/**/*.ts"],
8
+ "exclude": ["node_modules", "dist"]
9
+ }
package/tsup.config.ts ADDED
@@ -0,0 +1,9 @@
1
+ import { defineConfig } from 'tsup'
2
+
3
+ export default defineConfig({
4
+ entry: ['index.ts', 'implements/**/*.ts'],
5
+ format: ['cjs', 'esm'],
6
+ dts: true,
7
+ sourcemap: true,
8
+ clean: true,
9
+ })