@flarcos/kiota-authentication-gnap 0.1.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.
Files changed (38) hide show
  1. package/README.md +192 -0
  2. package/dist/contentDigest.d.ts +17 -0
  3. package/dist/contentDigest.d.ts.map +1 -0
  4. package/dist/contentDigest.js +23 -0
  5. package/dist/contentDigest.js.map +1 -0
  6. package/dist/errors.d.ts +25 -0
  7. package/dist/errors.d.ts.map +1 -0
  8. package/dist/errors.js +46 -0
  9. package/dist/errors.js.map +1 -0
  10. package/dist/gnapAccessTokenProvider.d.ts +50 -0
  11. package/dist/gnapAccessTokenProvider.d.ts.map +1 -0
  12. package/dist/gnapAccessTokenProvider.js +176 -0
  13. package/dist/gnapAccessTokenProvider.js.map +1 -0
  14. package/dist/gnapAuthenticationProvider.d.ts +68 -0
  15. package/dist/gnapAuthenticationProvider.d.ts.map +1 -0
  16. package/dist/gnapAuthenticationProvider.js +216 -0
  17. package/dist/gnapAuthenticationProvider.js.map +1 -0
  18. package/dist/gnapTokenStore.d.ts +11 -0
  19. package/dist/gnapTokenStore.d.ts.map +1 -0
  20. package/dist/gnapTokenStore.js +27 -0
  21. package/dist/gnapTokenStore.js.map +1 -0
  22. package/dist/httpMessageSigner.d.ts +41 -0
  23. package/dist/httpMessageSigner.d.ts.map +1 -0
  24. package/dist/httpMessageSigner.js +74 -0
  25. package/dist/httpMessageSigner.js.map +1 -0
  26. package/dist/index.d.ts +20 -0
  27. package/dist/index.d.ts.map +1 -0
  28. package/dist/index.js +25 -0
  29. package/dist/index.js.map +1 -0
  30. package/dist/keyManagement.d.ts +36 -0
  31. package/dist/keyManagement.d.ts.map +1 -0
  32. package/dist/keyManagement.js +75 -0
  33. package/dist/keyManagement.js.map +1 -0
  34. package/dist/types.d.ts +145 -0
  35. package/dist/types.d.ts.map +1 -0
  36. package/dist/types.js +6 -0
  37. package/dist/types.js.map +1 -0
  38. package/package.json +44 -0
@@ -0,0 +1,216 @@
1
+ /**
2
+ * GNAP Authentication Provider for Kiota.
3
+ *
4
+ * Implements the Kiota AuthenticationProvider interface to authenticate
5
+ * requests using the GNAP protocol (RFC 9635) with HTTP Message Signatures
6
+ * (RFC 9421).
7
+ *
8
+ * This is the main entry point for the package. Usage:
9
+ *
10
+ * ```typescript
11
+ * import { GnapAuthenticationProvider } from "@flarcos/kiota-authentication-gnap";
12
+ *
13
+ * const authProvider = new GnapAuthenticationProvider({
14
+ * authServerUrl: "https://auth.wallet.example/.well-known/...",
15
+ * privateKey: fs.readFileSync("private-key.pem", "utf-8"),
16
+ * clientIdentifier: "https://wallet.example/alice",
17
+ * accessRights: [{ type: "outgoing-payment", actions: ["create", "read"] }],
18
+ * });
19
+ *
20
+ * const adapter = new FetchRequestAdapter(authProvider);
21
+ * const client = new OpenPaymentsClient(adapter);
22
+ * ```
23
+ */
24
+ import { GnapAccessTokenProvider, } from "./gnapAccessTokenProvider.js";
25
+ import { InMemoryGnapTokenStore } from "./gnapTokenStore.js";
26
+ import { createHttpSignature } from "./httpMessageSigner.js";
27
+ import { computeContentDigest } from "./contentDigest.js";
28
+ import { loadPrivateKey, createGnapClientKey } from "./keyManagement.js";
29
+ import { GnapInteractionRequiredError, GnapError, } from "./errors.js";
30
+ export class GnapAuthenticationProvider {
31
+ authServerUrl;
32
+ clientIdentifier;
33
+ accessRights;
34
+ interact;
35
+ interactionHandler;
36
+ tokenStore;
37
+ allowedHosts;
38
+ tokenProvider;
39
+ // Initialized lazily on first use
40
+ keyPromise = null;
41
+ rawKey;
42
+ constructor(options) {
43
+ this.authServerUrl = options.authServerUrl;
44
+ this.clientIdentifier = options.clientIdentifier;
45
+ this.accessRights = options.accessRights;
46
+ this.interact = options.interact;
47
+ this.interactionHandler = options.interactionHandler;
48
+ this.tokenStore = options.tokenStore ?? new InMemoryGnapTokenStore();
49
+ this.allowedHosts = new Set(options.allowedHosts ?? []);
50
+ this.tokenProvider = new GnapAccessTokenProvider();
51
+ this.rawKey = options.privateKey;
52
+ }
53
+ /**
54
+ * Lazily initialize the key material.
55
+ */
56
+ async getKeyMaterial() {
57
+ if (!this.keyPromise) {
58
+ this.keyPromise = (async () => {
59
+ const privateKey = await loadPrivateKey(this.rawKey);
60
+ const { jwk, keyId } = await createGnapClientKey(privateKey);
61
+ return { privateKey, jwk, keyId };
62
+ })();
63
+ }
64
+ return this.keyPromise;
65
+ }
66
+ /**
67
+ * Authenticate a Kiota request by:
68
+ * 1. Obtaining/caching a GNAP access token
69
+ * 2. Setting the Authorization: GNAP header
70
+ * 3. Computing Content-Digest for request bodies
71
+ * 4. Signing the request with HTTP Message Signatures
72
+ */
73
+ authenticateRequest = async (request, additionalAuthenticationContext) => {
74
+ if (!request) {
75
+ throw new GnapError("Request information cannot be null");
76
+ }
77
+ // Check allowed hosts
78
+ if (this.allowedHosts.size > 0) {
79
+ const url = new URL(request.URL);
80
+ if (!this.allowedHosts.has(url.host)) {
81
+ return; // Skip auth for non-allowed hosts
82
+ }
83
+ }
84
+ const { privateKey, jwk, keyId } = await this.getKeyMaterial();
85
+ // Step 1: Get or obtain an access token
86
+ const token = await this.getAccessToken(privateKey, jwk, keyId);
87
+ // Step 2: Set Authorization header
88
+ request.headers.add("Authorization", `GNAP ${token.value}`);
89
+ // Step 3: Compute Content-Digest if body is present
90
+ const method = request.httpMethod?.toString() ?? "GET";
91
+ const bodyContent = request.content;
92
+ let hasBody = false;
93
+ if (bodyContent && bodyContent.byteLength > 0) {
94
+ hasBody = true;
95
+ const digest = computeContentDigest(new Uint8Array(bodyContent));
96
+ request.headers.add("Content-Digest", digest);
97
+ }
98
+ // Step 4: Sign the request
99
+ const headersMap = new Map();
100
+ // Extract existing headers from RequestInformation
101
+ const headersIterator = request.headers.entries();
102
+ let headerEntry = headersIterator.next();
103
+ while (!headerEntry.done) {
104
+ const [key, values] = headerEntry.value;
105
+ if (values.size > 0) {
106
+ // Use the first value
107
+ headersMap.set(key.toLowerCase(), values.values().next().value);
108
+ }
109
+ headerEntry = headersIterator.next();
110
+ }
111
+ const { signature, signatureInput } = await createHttpSignature({
112
+ privateKey,
113
+ keyId,
114
+ method,
115
+ targetUri: request.URL,
116
+ headers: headersMap,
117
+ hasBody,
118
+ });
119
+ request.headers.add("Signature", signature);
120
+ request.headers.add("Signature-Input", signatureInput);
121
+ };
122
+ /**
123
+ * Get an access token — either from cache or by negotiating a new grant.
124
+ */
125
+ async getAccessToken(privateKey, jwk, keyId) {
126
+ // Try cache first
127
+ const cached = await this.tokenStore.get(this.authServerUrl);
128
+ if (cached) {
129
+ return cached.token;
130
+ }
131
+ // Request new grant
132
+ try {
133
+ const token = await this.tokenProvider.requestGrant({
134
+ authServerUrl: this.authServerUrl,
135
+ clientIdentifier: this.clientIdentifier,
136
+ clientKeyJwk: jwk,
137
+ privateKey,
138
+ keyId,
139
+ accessRights: this.accessRights,
140
+ interact: this.interact,
141
+ });
142
+ // Cache the token
143
+ await this.tokenStore.set(this.authServerUrl, {
144
+ token,
145
+ acquiredAt: Date.now(),
146
+ authServerUrl: this.authServerUrl,
147
+ });
148
+ return token;
149
+ }
150
+ catch (error) {
151
+ if (error instanceof GnapInteractionRequiredError) {
152
+ return this.handleInteraction(error, privateKey, keyId);
153
+ }
154
+ throw error;
155
+ }
156
+ }
157
+ /**
158
+ * Handle interactive grants (redirect-based user consent).
159
+ */
160
+ async handleInteraction(error, privateKey, keyId) {
161
+ if (!this.interactionHandler) {
162
+ throw new GnapError("Grant requires user interaction but no InteractionHandler is configured. " +
163
+ `Redirect URL: ${error.redirectUrl}`);
164
+ }
165
+ // Delegate to the interaction handler
166
+ const result = await this.interactionHandler.handleRedirect(error.redirectUrl, error.finishNonce ?? "");
167
+ // Continue the grant with the interact_ref
168
+ const token = await this.tokenProvider.continueGrant(error.continueUri, error.continueAccessToken, result.interactRef, privateKey, keyId);
169
+ // Cache the token
170
+ await this.tokenStore.set(this.authServerUrl, {
171
+ token,
172
+ acquiredAt: Date.now(),
173
+ authServerUrl: this.authServerUrl,
174
+ continueUri: error.continueUri,
175
+ continueAccessToken: error.continueAccessToken,
176
+ });
177
+ return token;
178
+ }
179
+ /**
180
+ * Rotate the current access token.
181
+ */
182
+ async rotateToken() {
183
+ const { privateKey, keyId } = await this.getKeyMaterial();
184
+ const cached = await this.tokenStore.get(this.authServerUrl);
185
+ if (!cached) {
186
+ throw new GnapError("No cached token to rotate");
187
+ }
188
+ if (!cached.token.manage) {
189
+ throw new GnapError("Token does not have a management URL");
190
+ }
191
+ const newToken = await this.tokenProvider.rotateToken(cached.token.manage, cached.token.value, privateKey, keyId);
192
+ await this.tokenStore.set(this.authServerUrl, {
193
+ token: newToken,
194
+ acquiredAt: Date.now(),
195
+ authServerUrl: this.authServerUrl,
196
+ continueUri: cached.continueUri,
197
+ continueAccessToken: cached.continueAccessToken,
198
+ });
199
+ return newToken;
200
+ }
201
+ /**
202
+ * Revoke the current access token.
203
+ */
204
+ async revokeToken() {
205
+ const { privateKey, keyId } = await this.getKeyMaterial();
206
+ const cached = await this.tokenStore.get(this.authServerUrl);
207
+ if (!cached) {
208
+ return; // Nothing to revoke
209
+ }
210
+ if (cached.token.manage) {
211
+ await this.tokenProvider.revokeToken(cached.token.manage, cached.token.value, privateKey, keyId);
212
+ }
213
+ await this.tokenStore.delete(this.authServerUrl);
214
+ }
215
+ }
216
+ //# sourceMappingURL=gnapAuthenticationProvider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gnapAuthenticationProvider.js","sourceRoot":"","sources":["../src/gnapAuthenticationProvider.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * In-memory GNAP token store.
3
+ */
4
+ import type { GnapTokenStore, StoredGnapToken } from "./types.js";
5
+ export declare class InMemoryGnapTokenStore implements GnapTokenStore {
6
+ private store;
7
+ get(key: string): Promise<StoredGnapToken | undefined>;
8
+ set(key: string, token: StoredGnapToken): Promise<void>;
9
+ delete(key: string): Promise<void>;
10
+ }
11
+ //# sourceMappingURL=gnapTokenStore.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gnapTokenStore.d.ts","sourceRoot":"","sources":["../src/gnapTokenStore.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAElE,qBAAa,sBAAuB,YAAW,cAAc;IAC3D,OAAO,CAAC,KAAK,CAAsC;IAE7C,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,GAAG,SAAS,CAAC;IAgBtD,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IAIvD,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAGzC"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * In-memory GNAP token store.
3
+ */
4
+ export class InMemoryGnapTokenStore {
5
+ store = new Map();
6
+ async get(key) {
7
+ const stored = this.store.get(key);
8
+ if (!stored)
9
+ return undefined;
10
+ // Check if token has expired
11
+ if (stored.token.expires_in) {
12
+ const elapsed = (Date.now() - stored.acquiredAt) / 1000;
13
+ if (elapsed >= stored.token.expires_in) {
14
+ this.store.delete(key);
15
+ return undefined;
16
+ }
17
+ }
18
+ return stored;
19
+ }
20
+ async set(key, token) {
21
+ this.store.set(key, token);
22
+ }
23
+ async delete(key) {
24
+ this.store.delete(key);
25
+ }
26
+ }
27
+ //# sourceMappingURL=gnapTokenStore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gnapTokenStore.js","sourceRoot":"","sources":["../src/gnapTokenStore.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,MAAM,OAAO,sBAAsB;IACzB,KAAK,GAAG,IAAI,GAAG,EAA2B,CAAC;IAEnD,KAAK,CAAC,GAAG,CAAC,GAAW;QACnB,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACnC,IAAI,CAAC,MAAM;YAAE,OAAO,SAAS,CAAC;QAE9B,6BAA6B;QAC7B,IAAI,MAAM,CAAC,KAAK,CAAC,UAAU,EAAE,CAAC;YAC5B,MAAM,OAAO,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,MAAM,CAAC,UAAU,CAAC,GAAG,IAAI,CAAC;YACxD,IAAI,OAAO,IAAI,MAAM,CAAC,KAAK,CAAC,UAAU,EAAE,CAAC;gBACvC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;gBACvB,OAAO,SAAS,CAAC;YACnB,CAAC;QACH,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,GAAW,EAAE,KAAsB;QAC3C,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IAC7B,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,GAAW;QACtB,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IACzB,CAAC;CACF"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * RFC 9421 HTTP Message Signatures for GNAP.
3
+ * @see https://www.rfc-editor.org/rfc/rfc9421.html
4
+ * @see https://www.rfc-editor.org/rfc/rfc9635.html#section-7.3.1
5
+ *
6
+ * Uses the `http-message-signatures` package (same as the official
7
+ * @interledger/http-signature-utils) for signature base construction
8
+ * and Ed25519 signing.
9
+ *
10
+ * Open Payments requires Ed25519-based signatures covering:
11
+ * - @method, @target-uri (always)
12
+ * - authorization (when token attached)
13
+ * - content-digest, content-length, content-type (when body present)
14
+ */
15
+ import { type KeyObject } from "node:crypto";
16
+ export interface SignatureParams {
17
+ /** The signing key */
18
+ privateKey: KeyObject;
19
+ /** The key ID (from wallet JWKS) */
20
+ keyId: string;
21
+ /** HTTP method (GET, POST, etc.) */
22
+ method: string;
23
+ /** Full target URI */
24
+ targetUri: string;
25
+ /** Request headers (key-value pairs) */
26
+ headers: Map<string, string>;
27
+ /** Whether the request has a body */
28
+ hasBody: boolean;
29
+ }
30
+ /**
31
+ * Signs an HTTP request per RFC 9421 and returns the Signature and
32
+ * Signature-Input header values.
33
+ *
34
+ * Uses the same signing library as the official @interledger/http-signature-utils
35
+ * to ensure full compatibility with the Open Payments authorization server.
36
+ */
37
+ export declare function createHttpSignature(params: SignatureParams): Promise<{
38
+ signature: string;
39
+ signatureInput: string;
40
+ }>;
41
+ //# sourceMappingURL=httpMessageSigner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"httpMessageSigner.d.ts","sourceRoot":"","sources":["../src/httpMessageSigner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,aAAa,CAAC;AAI7C,MAAM,WAAW,eAAe;IAC9B,sBAAsB;IACtB,UAAU,EAAE,SAAS,CAAC;IACtB,oCAAoC;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,oCAAoC;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,sBAAsB;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,wCAAwC;IACxC,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,qCAAqC;IACrC,OAAO,EAAE,OAAO,CAAC;CAClB;AAED;;;;;;GAMG;AACH,wBAAsB,mBAAmB,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC;IAC1E,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;CACxB,CAAC,CA4DD"}
@@ -0,0 +1,74 @@
1
+ /**
2
+ * RFC 9421 HTTP Message Signatures for GNAP.
3
+ * @see https://www.rfc-editor.org/rfc/rfc9421.html
4
+ * @see https://www.rfc-editor.org/rfc/rfc9635.html#section-7.3.1
5
+ *
6
+ * Uses the `http-message-signatures` package (same as the official
7
+ * @interledger/http-signature-utils) for signature base construction
8
+ * and Ed25519 signing.
9
+ *
10
+ * Open Payments requires Ed25519-based signatures covering:
11
+ * - @method, @target-uri (always)
12
+ * - authorization (when token attached)
13
+ * - content-digest, content-length, content-type (when body present)
14
+ */
15
+ import { createSigner, httpbis } from "http-message-signatures";
16
+ import { GnapSignatureError } from "./errors.js";
17
+ /**
18
+ * Signs an HTTP request per RFC 9421 and returns the Signature and
19
+ * Signature-Input header values.
20
+ *
21
+ * Uses the same signing library as the official @interledger/http-signature-utils
22
+ * to ensure full compatibility with the Open Payments authorization server.
23
+ */
24
+ export async function createHttpSignature(params) {
25
+ const { privateKey, keyId, method, targetUri, headers, hasBody } = params;
26
+ // Build the list of covered components — order matters
27
+ // Matches @interledger/http-signature-utils exactly
28
+ const components = ["@method", "@target-uri"];
29
+ // Always include authorization if present
30
+ if (headers.has("authorization")) {
31
+ components.push("authorization");
32
+ }
33
+ // Include body-related components when a body is present
34
+ // Order: content-digest, content-length, content-type
35
+ if (hasBody) {
36
+ if (headers.has("content-digest")) {
37
+ components.push("content-digest");
38
+ }
39
+ if (headers.has("content-length")) {
40
+ components.push("content-length");
41
+ }
42
+ if (headers.has("content-type")) {
43
+ components.push("content-type");
44
+ }
45
+ }
46
+ try {
47
+ // Create the signer using the same API as the official OP implementation
48
+ const signingKey = createSigner(privateKey, "ed25519", keyId);
49
+ // Convert our Map to a plain object for the http-message-signatures lib
50
+ const headersObj = {};
51
+ for (const [key, value] of headers) {
52
+ headersObj[key] = value;
53
+ }
54
+ // Sign using httpbis (RFC 9421) mode
55
+ const { headers: signedHeaders } = await httpbis.signMessage({
56
+ key: signingKey,
57
+ name: "sig1",
58
+ params: ["keyid", "created"],
59
+ fields: components,
60
+ }, {
61
+ method,
62
+ url: targetUri,
63
+ headers: headersObj,
64
+ });
65
+ return {
66
+ signature: signedHeaders["Signature"],
67
+ signatureInput: signedHeaders["Signature-Input"],
68
+ };
69
+ }
70
+ catch (error) {
71
+ throw new GnapSignatureError(`Failed to sign request: ${error instanceof Error ? error.message : String(error)}`);
72
+ }
73
+ }
74
+ //# sourceMappingURL=httpMessageSigner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"httpMessageSigner.js","sourceRoot":"","sources":["../src/httpMessageSigner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAiBjD;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,MAAuB;IAI/D,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,MAAM,CAAC;IAE1E,uDAAuD;IACvD,oDAAoD;IACpD,MAAM,UAAU,GAAa,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC;IAExD,0CAA0C;IAC1C,IAAI,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,EAAE,CAAC;QACjC,UAAU,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;IACnC,CAAC;IAED,yDAAyD;IACzD,sDAAsD;IACtD,IAAI,OAAO,EAAE,CAAC;QACZ,IAAI,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,EAAE,CAAC;YAClC,UAAU,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;QACpC,CAAC;QACD,IAAI,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,EAAE,CAAC;YAClC,UAAU,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;QACpC,CAAC;QACD,IAAI,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,EAAE,CAAC;YAChC,UAAU,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QAClC,CAAC;IACH,CAAC;IAED,IAAI,CAAC;QACH,yEAAyE;QACzE,MAAM,UAAU,GAAG,YAAY,CAAC,UAAU,EAAE,SAAS,EAAE,KAAK,CAAC,CAAC;QAE9D,wEAAwE;QACxE,MAAM,UAAU,GAA2B,EAAE,CAAC;QAC9C,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,OAAO,EAAE,CAAC;YACnC,UAAU,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;QAC1B,CAAC;QAED,qCAAqC;QACrC,MAAM,EAAE,OAAO,EAAE,aAAa,EAAE,GAAG,MAAM,OAAO,CAAC,WAAW,CAC1D;YACE,GAAG,EAAE,UAAU;YACf,IAAI,EAAE,MAAM;YACZ,MAAM,EAAE,CAAC,OAAO,EAAE,SAAS,CAAC;YAC5B,MAAM,EAAE,UAAU;SACnB,EACD;YACE,MAAM;YACN,GAAG,EAAE,SAAS;YACd,OAAO,EAAE,UAAU;SACpB,CACF,CAAC;QAEF,OAAO;YACL,SAAS,EAAE,aAAa,CAAC,WAAW,CAAW;YAC/C,cAAc,EAAE,aAAa,CAAC,iBAAiB,CAAW;SAC3D,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,kBAAkB,CAC1B,2BAA2B,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CACpF,CAAC;IACJ,CAAC;AACH,CAAC"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * @flarcos/kiota-authentication-gnap
3
+ *
4
+ * GNAP (RFC 9635) Authentication Provider for Microsoft Kiota.
5
+ * Enables Kiota-generated API clients to authenticate using the
6
+ * Grant Negotiation and Authorization Protocol with HTTP Message
7
+ * Signatures (RFC 9421).
8
+ *
9
+ * @packageDocumentation
10
+ */
11
+ export { GnapAuthenticationProvider } from "./gnapAuthenticationProvider.js";
12
+ export { GnapAccessTokenProvider } from "./gnapAccessTokenProvider.js";
13
+ export { InMemoryGnapTokenStore } from "./gnapTokenStore.js";
14
+ export { createHttpSignature } from "./httpMessageSigner.js";
15
+ export type { SignatureParams } from "./httpMessageSigner.js";
16
+ export { computeContentDigest, computeContentDigestFromString, } from "./contentDigest.js";
17
+ export { loadPrivateKey, derivePublicKey, exportPublicKeyJwk, computeJwkThumbprint, createGnapClientKey, } from "./keyManagement.js";
18
+ export { GnapError, GnapGrantError, GnapInteractionRequiredError, GnapTokenExpiredError, GnapSignatureError, } from "./errors.js";
19
+ export type { GnapClientKey, GnapClientInstance, GnapAccessRight, GnapGrantRequest, GnapAccessToken, GnapGrantResponse, StoredGnapToken, InteractionResult, GnapAuthenticationProviderOptions, InteractionHandler, GnapTokenStore, } from "./types.js";
20
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,EAAE,0BAA0B,EAAE,MAAM,iCAAiC,CAAC;AAG7E,OAAO,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AAGvE,OAAO,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAG7D,OAAO,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAC7D,YAAY,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAG9D,OAAO,EACL,oBAAoB,EACpB,8BAA8B,GAC/B,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EACL,cAAc,EACd,eAAe,EACf,kBAAkB,EAClB,oBAAoB,EACpB,mBAAmB,GACpB,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EACL,SAAS,EACT,cAAc,EACd,4BAA4B,EAC5B,qBAAqB,EACrB,kBAAkB,GACnB,MAAM,aAAa,CAAC;AAGrB,YAAY,EACV,aAAa,EACb,kBAAkB,EAClB,eAAe,EACf,gBAAgB,EAChB,eAAe,EACf,iBAAiB,EACjB,eAAe,EACf,iBAAiB,EACjB,iCAAiC,EACjC,kBAAkB,EAClB,cAAc,GACf,MAAM,YAAY,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,25 @@
1
+ /**
2
+ * @flarcos/kiota-authentication-gnap
3
+ *
4
+ * GNAP (RFC 9635) Authentication Provider for Microsoft Kiota.
5
+ * Enables Kiota-generated API clients to authenticate using the
6
+ * Grant Negotiation and Authorization Protocol with HTTP Message
7
+ * Signatures (RFC 9421).
8
+ *
9
+ * @packageDocumentation
10
+ */
11
+ // Main provider
12
+ export { GnapAuthenticationProvider } from "./gnapAuthenticationProvider.js";
13
+ // Access token lifecycle
14
+ export { GnapAccessTokenProvider } from "./gnapAccessTokenProvider.js";
15
+ // Token storage
16
+ export { InMemoryGnapTokenStore } from "./gnapTokenStore.js";
17
+ // HTTP Message Signatures (RFC 9421)
18
+ export { createHttpSignature } from "./httpMessageSigner.js";
19
+ // Content-Digest (RFC 9530)
20
+ export { computeContentDigest, computeContentDigestFromString, } from "./contentDigest.js";
21
+ // Key management
22
+ export { loadPrivateKey, derivePublicKey, exportPublicKeyJwk, computeJwkThumbprint, createGnapClientKey, } from "./keyManagement.js";
23
+ // Errors
24
+ export { GnapError, GnapGrantError, GnapInteractionRequiredError, GnapTokenExpiredError, GnapSignatureError, } from "./errors.js";
25
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,gBAAgB;AAChB,OAAO,EAAE,0BAA0B,EAAE,MAAM,iCAAiC,CAAC;AAE7E,yBAAyB;AACzB,OAAO,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AAEvE,gBAAgB;AAChB,OAAO,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAE7D,qCAAqC;AACrC,OAAO,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAG7D,4BAA4B;AAC5B,OAAO,EACL,oBAAoB,EACpB,8BAA8B,GAC/B,MAAM,oBAAoB,CAAC;AAE5B,iBAAiB;AACjB,OAAO,EACL,cAAc,EACd,eAAe,EACf,kBAAkB,EAClB,oBAAoB,EACpB,mBAAmB,GACpB,MAAM,oBAAoB,CAAC;AAE5B,SAAS;AACT,OAAO,EACL,SAAS,EACT,cAAc,EACd,4BAA4B,EAC5B,qBAAqB,EACrB,kBAAkB,GACnB,MAAM,aAAa,CAAC"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Ed25519 key management utilities.
3
+ * Handles key loading, JWK conversion, and JWK thumbprint computation.
4
+ */
5
+ import { type KeyObject } from "node:crypto";
6
+ /**
7
+ * Load an Ed25519 private key from PEM string or CryptoKey.
8
+ */
9
+ export declare function loadPrivateKey(key: CryptoKey | string): Promise<KeyObject>;
10
+ /**
11
+ * Derive the public key from a private key.
12
+ */
13
+ export declare function derivePublicKey(privateKey: KeyObject): KeyObject;
14
+ /**
15
+ * Export a KeyObject to JWK format.
16
+ */
17
+ export declare function exportPublicKeyJwk(privateKey: KeyObject): Promise<JsonWebKey>;
18
+ /**
19
+ * Compute the JWK Thumbprint (RFC 7638) for an Ed25519 public key.
20
+ * Used as the `keyid` in HTTP Message Signatures.
21
+ *
22
+ * For OKP (Ed25519) keys, the thumbprint input is:
23
+ * {"crv":"Ed25519","kty":"OKP","x":"<base64url>"}
24
+ *
25
+ * @see https://www.rfc-editor.org/rfc/rfc7638.html
26
+ */
27
+ export declare function computeJwkThumbprint(jwk: JsonWebKey): string;
28
+ /**
29
+ * Create a complete GnapClientKey from a KeyObject.
30
+ */
31
+ export declare function createGnapClientKey(privateKey: KeyObject): Promise<{
32
+ jwk: JsonWebKey;
33
+ keyId: string;
34
+ privateKey: KeyObject;
35
+ }>;
36
+ //# sourceMappingURL=keyManagement.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keyManagement.d.ts","sourceRoot":"","sources":["../src/keyManagement.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAqC,KAAK,SAAS,EAAE,MAAM,aAAa,CAAC;AAIhF;;GAEG;AACH,wBAAsB,cAAc,CAClC,GAAG,EAAE,SAAS,GAAG,MAAM,GACtB,OAAO,CAAC,SAAS,CAAC,CAapB;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,UAAU,EAAE,SAAS,GAAG,SAAS,CAEhE;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CACtC,UAAU,EAAE,SAAS,GACpB,OAAO,CAAC,UAAU,CAAC,CAIrB;AAED;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,UAAU,GAAG,MAAM,CAmB5D;AAED;;GAEG;AACH,wBAAsB,mBAAmB,CAAC,UAAU,EAAE,SAAS;;;;GAS9D"}
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Ed25519 key management utilities.
3
+ * Handles key loading, JWK conversion, and JWK thumbprint computation.
4
+ */
5
+ import { createPrivateKey, createPublicKey } from "node:crypto";
6
+ import { createHash } from "node:crypto";
7
+ /**
8
+ * Load an Ed25519 private key from PEM string or CryptoKey.
9
+ */
10
+ export async function loadPrivateKey(key) {
11
+ if (typeof key === "string") {
12
+ // PEM format
13
+ return createPrivateKey({
14
+ key,
15
+ format: "pem",
16
+ type: "pkcs8",
17
+ });
18
+ }
19
+ // Already a CryptoKey — this shouldn't happen in Node, but handle gracefully
20
+ throw new Error("CryptoKey is not supported in Node.js. Please provide a PEM string.");
21
+ }
22
+ /**
23
+ * Derive the public key from a private key.
24
+ */
25
+ export function derivePublicKey(privateKey) {
26
+ return createPublicKey(privateKey);
27
+ }
28
+ /**
29
+ * Export a KeyObject to JWK format.
30
+ */
31
+ export async function exportPublicKeyJwk(privateKey) {
32
+ const publicKey = derivePublicKey(privateKey);
33
+ const jwk = publicKey.export({ format: "jwk" });
34
+ return jwk;
35
+ }
36
+ /**
37
+ * Compute the JWK Thumbprint (RFC 7638) for an Ed25519 public key.
38
+ * Used as the `keyid` in HTTP Message Signatures.
39
+ *
40
+ * For OKP (Ed25519) keys, the thumbprint input is:
41
+ * {"crv":"Ed25519","kty":"OKP","x":"<base64url>"}
42
+ *
43
+ * @see https://www.rfc-editor.org/rfc/rfc7638.html
44
+ */
45
+ export function computeJwkThumbprint(jwk) {
46
+ // Per RFC 7638 §3.2: lexicographic ordering of required members
47
+ // For OKP: crv, kty, x
48
+ const thumbprintInput = JSON.stringify({
49
+ crv: jwk.crv,
50
+ kty: jwk.kty,
51
+ x: jwk.x,
52
+ });
53
+ const hash = createHash("sha-256")
54
+ .update(thumbprintInput, "utf-8")
55
+ .digest();
56
+ // Base64url encode
57
+ return hash
58
+ .toString("base64")
59
+ .replace(/\+/g, "-")
60
+ .replace(/\//g, "_")
61
+ .replace(/=+$/, "");
62
+ }
63
+ /**
64
+ * Create a complete GnapClientKey from a KeyObject.
65
+ */
66
+ export async function createGnapClientKey(privateKey) {
67
+ const jwk = await exportPublicKeyJwk(privateKey);
68
+ const keyId = computeJwkThumbprint(jwk);
69
+ return {
70
+ jwk,
71
+ keyId,
72
+ privateKey,
73
+ };
74
+ }
75
+ //# sourceMappingURL=keyManagement.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keyManagement.js","sourceRoot":"","sources":["../src/keyManagement.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAkB,MAAM,aAAa,CAAC;AAChF,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAGzC;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,GAAuB;IAEvB,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;QAC5B,aAAa;QACb,OAAO,gBAAgB,CAAC;YACtB,GAAG;YACH,MAAM,EAAE,KAAK;YACb,IAAI,EAAE,OAAO;SACd,CAAC,CAAC;IACL,CAAC;IACD,6EAA6E;IAC7E,MAAM,IAAI,KAAK,CACb,qEAAqE,CACtE,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,UAAqB;IACnD,OAAO,eAAe,CAAC,UAAU,CAAC,CAAC;AACrC,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,UAAqB;IAErB,MAAM,SAAS,GAAG,eAAe,CAAC,UAAU,CAAC,CAAC;IAC9C,MAAM,GAAG,GAAG,SAAS,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;IAChD,OAAO,GAAiB,CAAC;AAC3B,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,oBAAoB,CAAC,GAAe;IAClD,gEAAgE;IAChE,uBAAuB;IACvB,MAAM,eAAe,GAAG,IAAI,CAAC,SAAS,CAAC;QACrC,GAAG,EAAE,GAAG,CAAC,GAAG;QACZ,GAAG,EAAE,GAAG,CAAC,GAAG;QACZ,CAAC,EAAG,GAA+B,CAAC,CAAC;KACtC,CAAC,CAAC;IAEH,MAAM,IAAI,GAAG,UAAU,CAAC,SAAS,CAAC;SAC/B,MAAM,CAAC,eAAe,EAAE,OAAO,CAAC;SAChC,MAAM,EAAE,CAAC;IAEZ,mBAAmB;IACnB,OAAO,IAAI;SACR,QAAQ,CAAC,QAAQ,CAAC;SAClB,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC;SACnB,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC;SACnB,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;AACxB,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,UAAqB;IAC7D,MAAM,GAAG,GAAG,MAAM,kBAAkB,CAAC,UAAU,CAAC,CAAC;IACjD,MAAM,KAAK,GAAG,oBAAoB,CAAC,GAAG,CAAC,CAAC;IAExC,OAAO;QACL,GAAG;QACH,KAAK;QACL,UAAU;KACX,CAAC;AACJ,CAAC"}