@kwirthmagnify/kwirth-common-back 0.5.18 → 0.5.19

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,2 @@
1
+ import { IIdpIdentity } from './IIdpConnector';
2
+ export declare function githubIdentityFromToken(apiBaseUrl: string, accessToken: string): Promise<IIdpIdentity>;
package/dist/github.js ADDED
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.githubIdentityFromToken = githubIdentityFromToken;
4
+ async function ghGet(base, resource, accessToken) {
5
+ const res = await fetch(`${base}${resource}`, {
6
+ headers: {
7
+ 'Authorization': `Bearer ${accessToken}`,
8
+ 'Accept': 'application/vnd.github+json',
9
+ 'User-Agent': 'kwirth'
10
+ }
11
+ });
12
+ if (!res.ok)
13
+ throw new Error(`GitHub API ${resource} returned ${res.status}`);
14
+ return res.json();
15
+ }
16
+ async function githubIdentityFromToken(apiBaseUrl, accessToken) {
17
+ const base = apiBaseUrl.replace(/\/+$/, '');
18
+ const user = await ghGet(base, '/user', accessToken);
19
+ // /user/emails puede fallar si falta el scope user:email; en ese caso caemos al email público
20
+ const emails = await ghGet(base, '/user/emails', accessToken).catch(() => []);
21
+ // preferimos el email primary; si no, el primero verificado; si no, el primero que haya
22
+ const chosen = emails.find(e => e.primary) ?? emails.find(e => e.verified) ?? emails[0];
23
+ return {
24
+ email: chosen?.email ?? user.email ?? '',
25
+ emailVerified: chosen?.verified === true,
26
+ name: user.name ?? user.login,
27
+ sub: user.id !== undefined ? String(user.id) : undefined
28
+ };
29
+ }
package/dist/index.d.ts CHANGED
@@ -4,5 +4,7 @@ export * from './IProvider';
4
4
  export * from './ISender';
5
5
  export * from './IIdpConnector';
6
6
  export * from './oidc';
7
+ export * from './oauth2';
8
+ export * from './github';
7
9
  export * from './KubernetesTools';
8
10
  export * from '@kwirthmagnify/kwirth-common';
package/dist/index.js CHANGED
@@ -20,5 +20,7 @@ __exportStar(require("./IProvider"), exports);
20
20
  __exportStar(require("./ISender"), exports);
21
21
  __exportStar(require("./IIdpConnector"), exports);
22
22
  __exportStar(require("./oidc"), exports);
23
+ __exportStar(require("./oauth2"), exports);
24
+ __exportStar(require("./github"), exports);
23
25
  __exportStar(require("./KubernetesTools"), exports);
24
26
  __exportStar(require("@kwirthmagnify/kwirth-common"), exports);
@@ -0,0 +1,10 @@
1
+ import { IIdpAuthContext, IIdpCallbackContext, IIdpConfigFieldDef, IIdpIdentity } from './IIdpConnector';
2
+ export interface IOAuth2Endpoints {
3
+ authorizationEndpoint: string;
4
+ tokenEndpoint: string;
5
+ defaultScopes?: string;
6
+ usePkce?: boolean;
7
+ }
8
+ export declare function oauth2ConfigSchema(): IIdpConfigFieldDef[];
9
+ export declare function oauth2BuildAuthorizationUrl(config: Record<string, unknown>, ctx: IIdpAuthContext, ep: IOAuth2Endpoints): string;
10
+ export declare function oauth2HandleCallback(config: Record<string, unknown>, ctx: IIdpCallbackContext, ep: IOAuth2Endpoints, fetchIdentity: (accessToken: string) => Promise<IIdpIdentity>): Promise<IIdpIdentity>;
package/dist/oauth2.js ADDED
@@ -0,0 +1,52 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.oauth2ConfigSchema = oauth2ConfigSchema;
4
+ exports.oauth2BuildAuthorizationUrl = oauth2BuildAuthorizationUrl;
5
+ exports.oauth2HandleCallback = oauth2HandleCallback;
6
+ // esquema base de un IdP OAuth2 (el conector añade sus URLs si aplica; clientSecret 'password' → se enmascara)
7
+ function oauth2ConfigSchema() {
8
+ return [
9
+ { name: 'clientId', label: 'Client ID', type: 'text', required: true },
10
+ { name: 'clientSecret', label: 'Client Secret', type: 'password', required: true },
11
+ { name: 'scopes', label: 'Scopes', type: 'text' }
12
+ ];
13
+ }
14
+ function oauth2BuildAuthorizationUrl(config, ctx, ep) {
15
+ const scope = config.scopes || ep.defaultScopes || '';
16
+ const url = new URL(ep.authorizationEndpoint);
17
+ url.searchParams.set('client_id', String(config.clientId ?? ''));
18
+ url.searchParams.set('redirect_uri', ctx.redirectUri);
19
+ url.searchParams.set('response_type', 'code');
20
+ url.searchParams.set('state', ctx.state);
21
+ if (scope)
22
+ url.searchParams.set('scope', scope);
23
+ if (ep.usePkce) {
24
+ url.searchParams.set('code_challenge', ctx.codeChallenge);
25
+ url.searchParams.set('code_challenge_method', 'S256');
26
+ }
27
+ return url.toString();
28
+ }
29
+ // intercambia el 'code' por access_token (back-channel) y delega el userinfo en fetchIdentity(accessToken).
30
+ async function oauth2HandleCallback(config, ctx, ep, fetchIdentity) {
31
+ const body = new URLSearchParams();
32
+ body.set('grant_type', 'authorization_code');
33
+ body.set('code', ctx.code);
34
+ body.set('client_id', String(config.clientId ?? ''));
35
+ body.set('client_secret', String(config.clientSecret ?? ''));
36
+ body.set('redirect_uri', ctx.redirectUri);
37
+ if (ep.usePkce)
38
+ body.set('code_verifier', ctx.codeVerifier);
39
+ // Accept: application/json → algunos IdP (GitHub) devuelven form-urlencoded sin esta cabecera
40
+ const res = await fetch(ep.tokenEndpoint, {
41
+ method: 'POST',
42
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'Accept': 'application/json' },
43
+ body
44
+ });
45
+ if (!res.ok)
46
+ throw new Error(`OAuth2 token endpoint returned ${res.status}`);
47
+ const token = await res.json();
48
+ if (token.error || !token.access_token) {
49
+ throw new Error(`OAuth2 token exchange failed: ${token.error_description || token.error || 'no access_token'}`);
50
+ }
51
+ return fetchIdentity(token.access_token);
52
+ }
package/package.json CHANGED
@@ -1,9 +1,10 @@
1
1
  {
2
2
  "name": "@kwirthmagnify/kwirth-common-back",
3
- "version": "0.5.18",
3
+ "version": "0.5.19",
4
4
  "description": "Backend interfaces for building Kwirth provider and channel plugins",
5
5
  "scripts": {
6
- "build": "tsc"
6
+ "build": "tsc",
7
+ "test": "node tests/run.mjs"
7
8
  },
8
9
  "publishConfig": {
9
10
  "access": "public",
@@ -33,6 +34,7 @@
33
34
  "devDependencies": {
34
35
  "@types/express": "^4.17.21",
35
36
  "@types/js-yaml": "^4.0.9",
37
+ "esbuild": "^0.27.2",
36
38
  "typescript": "^5.8.3"
37
39
  }
38
40
  }