@memberjunction/server 5.39.0 → 5.40.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/dist/auth/index.js +1 -1
- package/dist/auth/index.js.map +1 -1
- package/dist/auth/magicLink/MagicLinkKeys.d.ts +58 -0
- package/dist/auth/magicLink/MagicLinkKeys.d.ts.map +1 -0
- package/dist/auth/magicLink/MagicLinkKeys.js +99 -0
- package/dist/auth/magicLink/MagicLinkKeys.js.map +1 -0
- package/dist/auth/magicLink/MagicLinkRouter.d.ts +33 -0
- package/dist/auth/magicLink/MagicLinkRouter.d.ts.map +1 -0
- package/dist/auth/magicLink/MagicLinkRouter.js +184 -0
- package/dist/auth/magicLink/MagicLinkRouter.js.map +1 -0
- package/dist/auth/magicLink/MagicLinkService.d.ts +123 -0
- package/dist/auth/magicLink/MagicLinkService.d.ts.map +1 -0
- package/dist/auth/magicLink/MagicLinkService.js +605 -0
- package/dist/auth/magicLink/MagicLinkService.js.map +1 -0
- package/dist/auth/magicLink/index.d.ts +6 -0
- package/dist/auth/magicLink/index.d.ts.map +1 -0
- package/dist/auth/magicLink/index.js +6 -0
- package/dist/auth/magicLink/index.js.map +1 -0
- package/dist/auth/magicLink/magicLinkCore.d.ts +82 -0
- package/dist/auth/magicLink/magicLinkCore.d.ts.map +1 -0
- package/dist/auth/magicLink/magicLinkCore.js +164 -0
- package/dist/auth/magicLink/magicLinkCore.js.map +1 -0
- package/dist/auth/magicLink/redeemLanding.d.ts +22 -0
- package/dist/auth/magicLink/redeemLanding.d.ts.map +1 -0
- package/dist/auth/magicLink/redeemLanding.js +61 -0
- package/dist/auth/magicLink/redeemLanding.js.map +1 -0
- package/dist/auth/magicLink/types.d.ts +131 -0
- package/dist/auth/magicLink/types.d.ts.map +1 -0
- package/dist/auth/magicLink/types.js +6 -0
- package/dist/auth/magicLink/types.js.map +1 -0
- package/dist/config.d.ts +411 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +60 -0
- package/dist/config.js.map +1 -1
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +225 -2
- package/dist/context.js.map +1 -1
- package/dist/generated/generated.d.ts +877 -4
- package/dist/generated/generated.d.ts.map +1 -1
- package/dist/generated/generated.js +17779 -12750
- package/dist/generated/generated.js.map +1 -1
- package/dist/generic/ResolverBase.d.ts.map +1 -1
- package/dist/generic/ResolverBase.js +35 -7
- package/dist/generic/ResolverBase.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +25 -0
- package/dist/index.js.map +1 -1
- package/dist/resolvers/CurrentUserContextResolver.d.ts +9 -3
- package/dist/resolvers/CurrentUserContextResolver.d.ts.map +1 -1
- package/dist/resolvers/CurrentUserContextResolver.js +19 -5
- package/dist/resolvers/CurrentUserContextResolver.js.map +1 -1
- package/dist/resolvers/EntityResolver.d.ts.map +1 -1
- package/dist/resolvers/EntityResolver.js +13 -2
- package/dist/resolvers/EntityResolver.js.map +1 -1
- package/dist/resolvers/GenerateSeedTaxonomyResolver.d.ts +28 -0
- package/dist/resolvers/GenerateSeedTaxonomyResolver.d.ts.map +1 -0
- package/dist/resolvers/GenerateSeedTaxonomyResolver.js +100 -0
- package/dist/resolvers/GenerateSeedTaxonomyResolver.js.map +1 -0
- package/dist/resolvers/RunClusterAnalysisResolver.d.ts +74 -0
- package/dist/resolvers/RunClusterAnalysisResolver.d.ts.map +1 -0
- package/dist/resolvers/RunClusterAnalysisResolver.js +243 -0
- package/dist/resolvers/RunClusterAnalysisResolver.js.map +1 -0
- package/dist/resolvers/UserResolver.d.ts +16 -2
- package/dist/resolvers/UserResolver.d.ts.map +1 -1
- package/dist/resolvers/UserResolver.js +45 -2
- package/dist/resolvers/UserResolver.js.map +1 -1
- package/dist/rest/SignatureWebhookHandler.d.ts +19 -0
- package/dist/rest/SignatureWebhookHandler.d.ts.map +1 -0
- package/dist/rest/SignatureWebhookHandler.js +86 -0
- package/dist/rest/SignatureWebhookHandler.js.map +1 -0
- package/package.json +75 -71
- package/src/__tests__/magicLink.test.ts +387 -0
- package/src/auth/index.ts +2 -2
- package/src/auth/magicLink/MagicLinkKeys.ts +122 -0
- package/src/auth/magicLink/MagicLinkRouter.ts +209 -0
- package/src/auth/magicLink/MagicLinkService.ts +724 -0
- package/src/auth/magicLink/index.ts +17 -0
- package/src/auth/magicLink/magicLinkCore.ts +216 -0
- package/src/auth/magicLink/redeemLanding.ts +62 -0
- package/src/auth/magicLink/types.ts +137 -0
- package/src/config.ts +62 -0
- package/src/context.ts +252 -3
- package/src/generated/generated.ts +12302 -8878
- package/src/generic/ResolverBase.ts +35 -7
- package/src/index.ts +28 -0
- package/src/resolvers/CurrentUserContextResolver.ts +21 -5
- package/src/resolvers/EntityResolver.ts +17 -5
- package/src/resolvers/GenerateSeedTaxonomyResolver.ts +90 -0
- package/src/resolvers/RunClusterAnalysisResolver.ts +249 -0
- package/src/resolvers/UserResolver.ts +38 -2
- package/src/rest/SignatureWebhookHandler.ts +103 -0
package/dist/auth/index.js
CHANGED
|
@@ -173,7 +173,7 @@ export const verifyUserRecord = async (email, firstName, lastName, requestDomain
|
|
|
173
173
|
initData.UserRoles = configInfo.userHandling.newUserRoles.map((role) => {
|
|
174
174
|
const roleInfo = md.Roles.find((r) => r.Name === role);
|
|
175
175
|
const roleID = roleInfo ? roleInfo.ID : '';
|
|
176
|
-
return { UserID: initData.ID,
|
|
176
|
+
return { UserID: initData.ID, Role: role, RoleID: roleID };
|
|
177
177
|
});
|
|
178
178
|
user = new UserInfo(Metadata.Provider, initData); // global-provider-ok: same JWT-validation context — no per-request provider yet
|
|
179
179
|
UserCache.Instance.Users.push(user);
|
package/dist/auth/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview RS256 key manager for magic-link session JWTs.
|
|
3
|
+
*
|
|
4
|
+
* MJ signs magic-link session tokens with an RS256 private key and publishes the
|
|
5
|
+
* matching public key at a JWKS endpoint. Registering the `magic-link` auth
|
|
6
|
+
* provider with that JWKS URL lets MJServer's standard issuer-driven validation
|
|
7
|
+
* verify the tokens with no special-casing.
|
|
8
|
+
*
|
|
9
|
+
* @module @memberjunction/server/auth/magicLink
|
|
10
|
+
*/
|
|
11
|
+
import { BaseSingleton } from '@memberjunction/global';
|
|
12
|
+
import type { MagicLinkJWTClaims } from './types.js';
|
|
13
|
+
/** A single JSON Web Key plus the metadata jwks-rsa needs to match it. */
|
|
14
|
+
interface PublishedJWK extends JsonWebKey {
|
|
15
|
+
kid: string;
|
|
16
|
+
use: 'sig';
|
|
17
|
+
alg: 'RS256';
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Manages the RS256 keypair used to sign and publish magic-link session tokens.
|
|
21
|
+
* Singleton so the keypair (and therefore the `kid`) is stable for the process
|
|
22
|
+
* lifetime — restarting with an ephemeral key invalidates outstanding sessions,
|
|
23
|
+
* which is the intended dev behavior and an acceptable production key-rotation
|
|
24
|
+
* mechanism.
|
|
25
|
+
*/
|
|
26
|
+
export declare class MagicLinkKeyManager extends BaseSingleton<MagicLinkKeyManager> {
|
|
27
|
+
private privateKeyPem;
|
|
28
|
+
private publicKey?;
|
|
29
|
+
private _kid;
|
|
30
|
+
private _initialized;
|
|
31
|
+
constructor();
|
|
32
|
+
static get Instance(): MagicLinkKeyManager;
|
|
33
|
+
get IsInitialized(): boolean;
|
|
34
|
+
get Kid(): string;
|
|
35
|
+
/**
|
|
36
|
+
* Initializes the keypair from a provided PEM (raw or base64-encoded) or, if
|
|
37
|
+
* none is supplied, generates an ephemeral 2048-bit RSA keypair. Idempotent.
|
|
38
|
+
*/
|
|
39
|
+
Initialize(privateKeyPem?: string): void;
|
|
40
|
+
/**
|
|
41
|
+
* Signs a set of magic-link claims and returns the compact JWT.
|
|
42
|
+
* `iat`/`exp` are expected to already be set on the claims.
|
|
43
|
+
*/
|
|
44
|
+
Sign(claims: MagicLinkJWTClaims): string;
|
|
45
|
+
/**
|
|
46
|
+
* Returns the JWKS document (public key set) for the JWKS endpoint.
|
|
47
|
+
*/
|
|
48
|
+
GetJWKS(): {
|
|
49
|
+
keys: PublishedJWK[];
|
|
50
|
+
};
|
|
51
|
+
private ensureInitialized;
|
|
52
|
+
/** Accepts raw PEM or base64-encoded PEM and returns raw PEM. */
|
|
53
|
+
private normalizePem;
|
|
54
|
+
/** Stable key id derived from the public key (SHA-256 of DER, base64url, truncated). */
|
|
55
|
+
private computeKid;
|
|
56
|
+
}
|
|
57
|
+
export {};
|
|
58
|
+
//# sourceMappingURL=MagicLinkKeys.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MagicLinkKeys.d.ts","sourceRoot":"","sources":["../../../src/auth/magicLink/MagicLinkKeys.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAIvD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAErD,0EAA0E;AAC1E,UAAU,YAAa,SAAQ,UAAU;IACvC,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,KAAK,CAAC;IACX,GAAG,EAAE,OAAO,CAAC;CACd;AAED;;;;;;GAMG;AACH,qBAAa,mBAAoB,SAAQ,aAAa,CAAC,mBAAmB,CAAC;IACzE,OAAO,CAAC,aAAa,CAAM;IAC3B,OAAO,CAAC,SAAS,CAAC,CAAY;IAC9B,OAAO,CAAC,IAAI,CAAM;IAClB,OAAO,CAAC,YAAY,CAAS;;IAQ7B,WAAkB,QAAQ,IAAI,mBAAmB,CAEhD;IAED,IAAW,aAAa,IAAI,OAAO,CAElC;IAED,IAAW,GAAG,IAAI,MAAM,CAEvB;IAED;;;OAGG;IACI,UAAU,CAAC,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI;IAyB/C;;;OAGG;IACI,IAAI,CAAC,MAAM,EAAE,kBAAkB,GAAG,MAAM;IAK/C;;OAEG;IACI,OAAO,IAAI;QAAE,IAAI,EAAE,YAAY,EAAE,CAAA;KAAE;IAM1C,OAAO,CAAC,iBAAiB;IAMzB,iEAAiE;IACjE,OAAO,CAAC,YAAY;IAOpB,wFAAwF;IACxF,OAAO,CAAC,UAAU;CAInB"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview RS256 key manager for magic-link session JWTs.
|
|
3
|
+
*
|
|
4
|
+
* MJ signs magic-link session tokens with an RS256 private key and publishes the
|
|
5
|
+
* matching public key at a JWKS endpoint. Registering the `magic-link` auth
|
|
6
|
+
* provider with that JWKS URL lets MJServer's standard issuer-driven validation
|
|
7
|
+
* verify the tokens with no special-casing.
|
|
8
|
+
*
|
|
9
|
+
* @module @memberjunction/server/auth/magicLink
|
|
10
|
+
*/
|
|
11
|
+
import { BaseSingleton } from '@memberjunction/global';
|
|
12
|
+
import { LogStatus } from '@memberjunction/core';
|
|
13
|
+
import { createPrivateKey, createPublicKey, generateKeyPairSync, createHash } from 'node:crypto';
|
|
14
|
+
import jwt from 'jsonwebtoken';
|
|
15
|
+
/**
|
|
16
|
+
* Manages the RS256 keypair used to sign and publish magic-link session tokens.
|
|
17
|
+
* Singleton so the keypair (and therefore the `kid`) is stable for the process
|
|
18
|
+
* lifetime — restarting with an ephemeral key invalidates outstanding sessions,
|
|
19
|
+
* which is the intended dev behavior and an acceptable production key-rotation
|
|
20
|
+
* mechanism.
|
|
21
|
+
*/
|
|
22
|
+
export class MagicLinkKeyManager extends BaseSingleton {
|
|
23
|
+
// Public to satisfy BaseSingleton.getInstance's `this: new () => T` constraint
|
|
24
|
+
// (matches the AuthProviderFactory singleton pattern).
|
|
25
|
+
constructor() {
|
|
26
|
+
super();
|
|
27
|
+
this.privateKeyPem = '';
|
|
28
|
+
this._kid = '';
|
|
29
|
+
this._initialized = false;
|
|
30
|
+
}
|
|
31
|
+
static get Instance() {
|
|
32
|
+
return MagicLinkKeyManager.getInstance();
|
|
33
|
+
}
|
|
34
|
+
get IsInitialized() {
|
|
35
|
+
return this._initialized;
|
|
36
|
+
}
|
|
37
|
+
get Kid() {
|
|
38
|
+
return this._kid;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Initializes the keypair from a provided PEM (raw or base64-encoded) or, if
|
|
42
|
+
* none is supplied, generates an ephemeral 2048-bit RSA keypair. Idempotent.
|
|
43
|
+
*/
|
|
44
|
+
Initialize(privateKeyPem) {
|
|
45
|
+
if (this._initialized) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
let priv;
|
|
49
|
+
const supplied = privateKeyPem?.trim();
|
|
50
|
+
if (supplied) {
|
|
51
|
+
priv = createPrivateKey(this.normalizePem(supplied));
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
const { privateKey } = generateKeyPairSync('rsa', { modulusLength: 2048 });
|
|
55
|
+
priv = privateKey;
|
|
56
|
+
LogStatus('[MagicLink] No rsaPrivateKey configured — generated an EPHEMERAL RS256 keypair. ' +
|
|
57
|
+
'Outstanding magic-link sessions will be invalidated on restart. Set magicLink.rsaPrivateKey ' +
|
|
58
|
+
'(or MJ_MAGIC_LINK_PRIVATE_KEY) for stable production keys.');
|
|
59
|
+
}
|
|
60
|
+
this.privateKeyPem = priv.export({ type: 'pkcs8', format: 'pem' });
|
|
61
|
+
this.publicKey = createPublicKey(priv);
|
|
62
|
+
this._kid = this.computeKid(this.publicKey);
|
|
63
|
+
this._initialized = true;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Signs a set of magic-link claims and returns the compact JWT.
|
|
67
|
+
* `iat`/`exp` are expected to already be set on the claims.
|
|
68
|
+
*/
|
|
69
|
+
Sign(claims) {
|
|
70
|
+
this.ensureInitialized();
|
|
71
|
+
return jwt.sign(claims, this.privateKeyPem, { algorithm: 'RS256', keyid: this._kid });
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Returns the JWKS document (public key set) for the JWKS endpoint.
|
|
75
|
+
*/
|
|
76
|
+
GetJWKS() {
|
|
77
|
+
this.ensureInitialized();
|
|
78
|
+
const jwk = this.publicKey.export({ format: 'jwk' });
|
|
79
|
+
return { keys: [{ ...jwk, kid: this._kid, use: 'sig', alg: 'RS256' }] };
|
|
80
|
+
}
|
|
81
|
+
ensureInitialized() {
|
|
82
|
+
if (!this._initialized) {
|
|
83
|
+
throw new Error('MagicLinkKeyManager not initialized — call Initialize() during server startup.');
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
/** Accepts raw PEM or base64-encoded PEM and returns raw PEM. */
|
|
87
|
+
normalizePem(value) {
|
|
88
|
+
if (value.includes('-----BEGIN')) {
|
|
89
|
+
return value;
|
|
90
|
+
}
|
|
91
|
+
return Buffer.from(value, 'base64').toString('utf8');
|
|
92
|
+
}
|
|
93
|
+
/** Stable key id derived from the public key (SHA-256 of DER, base64url, truncated). */
|
|
94
|
+
computeKid(publicKey) {
|
|
95
|
+
const pem = publicKey.export({ type: 'spki', format: 'pem' });
|
|
96
|
+
return createHash('sha256').update(pem).digest('base64url').slice(0, 16);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=MagicLinkKeys.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MagicLinkKeys.js","sourceRoot":"","sources":["../../../src/auth/magicLink/MagicLinkKeys.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Express wiring + auth-provider registration for magic links.
|
|
3
|
+
*
|
|
4
|
+
* Mirrors the OAuth handler pattern: a public router (unauthenticated — JWKS +
|
|
5
|
+
* redeem) mounted BEFORE the unified auth middleware, and an authenticated
|
|
6
|
+
* router (invite creation) mounted AFTER it so `req.userPayload` is available.
|
|
7
|
+
*
|
|
8
|
+
* @module @memberjunction/server/auth/magicLink
|
|
9
|
+
*/
|
|
10
|
+
import { Router } from 'express';
|
|
11
|
+
import { type MagicLinkConfig } from '../../config.js';
|
|
12
|
+
/** The mount path for both routers (`/magic-link`). */
|
|
13
|
+
export declare const MAGIC_LINK_MOUNT_PATH = "/magic-link";
|
|
14
|
+
/** Path of the JWKS endpoint relative to the public URL. */
|
|
15
|
+
export declare const MAGIC_LINK_JWKS_PATH = "/magic-link/jwks.json";
|
|
16
|
+
/**
|
|
17
|
+
* Builds the magic-link routers. The caller mounts `publicRouter` before the
|
|
18
|
+
* auth middleware and `authenticatedRouter` after it (both at MAGIC_LINK_MOUNT_PATH).
|
|
19
|
+
*/
|
|
20
|
+
export declare function createMagicLinkHandler(publicUrl: string, config: MagicLinkConfig): {
|
|
21
|
+
publicRouter: Router;
|
|
22
|
+
authenticatedRouter: Router;
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Registers the `magic-link` auth provider so MJServer's issuer-driven JWT
|
|
26
|
+
* validation accepts MJ-issued session tokens. Issuer = public URL, JWKS URL =
|
|
27
|
+
* the public JWKS endpoint, audience = configured magic-link audience.
|
|
28
|
+
*
|
|
29
|
+
* Also appends the provider to `configInfo.authProviders` so a later
|
|
30
|
+
* `initializeAuthProviders()` (which clears + repopulates from config) keeps it.
|
|
31
|
+
*/
|
|
32
|
+
export declare function registerMagicLinkAuthProvider(publicUrl: string, config: MagicLinkConfig): void;
|
|
33
|
+
//# sourceMappingURL=MagicLinkRouter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MagicLinkRouter.d.ts","sourceRoot":"","sources":["../../../src/auth/magicLink/MagicLinkRouter.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,MAAM,EAAiD,MAAM,SAAS,CAAC;AAIhF,OAAO,EAAc,KAAK,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAMnE,uDAAuD;AACvD,eAAO,MAAM,qBAAqB,gBAAgB,CAAC;AAEnD,4DAA4D;AAC5D,eAAO,MAAM,oBAAoB,0BAAuC,CAAC;AAEzE;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,eAAe,GAAG;IAClF,YAAY,EAAE,MAAM,CAAC;IACrB,mBAAmB,EAAE,MAAM,CAAC;CAC7B,CAgJA;AAED;;;;;;;GAOG;AACH,wBAAgB,6BAA6B,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,eAAe,GAAG,IAAI,CAqB9F"}
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Express wiring + auth-provider registration for magic links.
|
|
3
|
+
*
|
|
4
|
+
* Mirrors the OAuth handler pattern: a public router (unauthenticated — JWKS +
|
|
5
|
+
* redeem) mounted BEFORE the unified auth middleware, and an authenticated
|
|
6
|
+
* router (invite creation) mounted AFTER it so `req.userPayload` is available.
|
|
7
|
+
*
|
|
8
|
+
* @module @memberjunction/server/auth/magicLink
|
|
9
|
+
*/
|
|
10
|
+
import { Router, json, urlencoded } from 'express';
|
|
11
|
+
import { rateLimit } from 'express-rate-limit';
|
|
12
|
+
import { LogError, LogStatus } from '@memberjunction/core';
|
|
13
|
+
import { AuthProviderFactory } from '@memberjunction/auth-providers';
|
|
14
|
+
import { configInfo } from '../../config.js';
|
|
15
|
+
import { MagicLinkKeyManager } from './MagicLinkKeys.js';
|
|
16
|
+
import { MagicLinkService } from './MagicLinkService.js';
|
|
17
|
+
import { buildRedeemLandingHtml } from './redeemLanding.js';
|
|
18
|
+
/** The mount path for both routers (`/magic-link`). */
|
|
19
|
+
export const MAGIC_LINK_MOUNT_PATH = '/magic-link';
|
|
20
|
+
/** Path of the JWKS endpoint relative to the public URL. */
|
|
21
|
+
export const MAGIC_LINK_JWKS_PATH = `${MAGIC_LINK_MOUNT_PATH}/jwks.json`;
|
|
22
|
+
/**
|
|
23
|
+
* Builds the magic-link routers. The caller mounts `publicRouter` before the
|
|
24
|
+
* auth middleware and `authenticatedRouter` after it (both at MAGIC_LINK_MOUNT_PATH).
|
|
25
|
+
*/
|
|
26
|
+
export function createMagicLinkHandler(publicUrl, config) {
|
|
27
|
+
// Initialize the signing keypair once.
|
|
28
|
+
MagicLinkKeyManager.Instance.Initialize(config.rsaPrivateKey);
|
|
29
|
+
const service = new MagicLinkService(publicUrl, config);
|
|
30
|
+
// Throttle the unauthenticated redemption endpoint and the authenticated
|
|
31
|
+
// create endpoint. /redeem is a public surface that does a DB lookup +
|
|
32
|
+
// (on a hit) user provisioning + token minting, so it must be rate-limited
|
|
33
|
+
// against guessing/enumeration/resource-exhaustion. Keyed by IP.
|
|
34
|
+
const redeemLimiter = rateLimit({
|
|
35
|
+
windowMs: config.rateLimitWindowMs,
|
|
36
|
+
limit: config.redeemRateLimitMax,
|
|
37
|
+
standardHeaders: 'draft-7',
|
|
38
|
+
legacyHeaders: false,
|
|
39
|
+
message: { success: false, errorCode: 'invalid', error: 'Too many redemption attempts. Try again later.' },
|
|
40
|
+
});
|
|
41
|
+
const createLimiter = rateLimit({
|
|
42
|
+
windowMs: config.rateLimitWindowMs,
|
|
43
|
+
limit: config.createRateLimitMax,
|
|
44
|
+
standardHeaders: 'draft-7',
|
|
45
|
+
legacyHeaders: false,
|
|
46
|
+
message: { success: false, error: 'Too many invite requests. Try again later.' },
|
|
47
|
+
});
|
|
48
|
+
// ── Public (unauthenticated) ──────────────────────────────────────────────
|
|
49
|
+
const publicRouter = Router();
|
|
50
|
+
publicRouter.get('/jwks.json', (_req, res) => {
|
|
51
|
+
res.status(200).json(MagicLinkKeyManager.Instance.GetJWKS());
|
|
52
|
+
});
|
|
53
|
+
// Sends a completed redemption result: browser flow → 302 into Explorer with
|
|
54
|
+
// the session token in the URL fragment (never sent to a server, so it stays
|
|
55
|
+
// out of access/proxy logs); API flow → JSON with an appropriate status.
|
|
56
|
+
const sendRedeemResult = (res, result, wantsJson) => {
|
|
57
|
+
const explorerUrl = config.explorerUrl?.replace(/\/$/, '');
|
|
58
|
+
if (explorerUrl && !wantsJson) {
|
|
59
|
+
if (result.success && result.token) {
|
|
60
|
+
// Deep-link into the invited app's route (e.g. /app/data-explorer) rather
|
|
61
|
+
// than Explorer's root — root falls through to Explorer's default resource,
|
|
62
|
+
// which isn't the scoped app. Use the app's URL Path (what Explorer's
|
|
63
|
+
// GetAppByPath matches on); fall back to a name-slug only when Path is
|
|
64
|
+
// absent. Do NOT hand-roll a slug from the name when Path exists — the two
|
|
65
|
+
// can diverge and Explorer would fail to resolve the app.
|
|
66
|
+
const appSlug = result.applicationPath
|
|
67
|
+
? result.applicationPath
|
|
68
|
+
: result.applicationName
|
|
69
|
+
? result.applicationName.trim().toLowerCase().replace(/\s+/g, '-')
|
|
70
|
+
: '';
|
|
71
|
+
const path = appSlug ? `/app/${encodeURIComponent(appSlug)}` : '/';
|
|
72
|
+
res.redirect(302, `${explorerUrl}${path}#token=${encodeURIComponent(result.token)}`);
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
res.redirect(302, `${explorerUrl}/?mlError=${encodeURIComponent(result.errorCode ?? 'invalid')}`);
|
|
76
|
+
}
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
// API/JSON flow.
|
|
80
|
+
// not_found / expired / consumed / revoked are client-side conditions (410 Gone);
|
|
81
|
+
// server_error / provisioning_failed are 500.
|
|
82
|
+
const status = result.success ? 200 : result.errorCode === 'server_error' || result.errorCode === 'provisioning_failed' ? 500 : 410;
|
|
83
|
+
res.status(status).json(result);
|
|
84
|
+
};
|
|
85
|
+
// GET /redeem is SAFE (no side effects). Link prefetchers and email security
|
|
86
|
+
// scanners routinely fetch URLs; a side-effectful GET would let them burn the
|
|
87
|
+
// single-use token before the human clicks. So GET renders an interstitial and
|
|
88
|
+
// the actual redemption happens only on POST (below), gated by a user click.
|
|
89
|
+
publicRouter.get('/redeem', redeemLimiter, (req, res) => {
|
|
90
|
+
const token = typeof req.query.token === 'string' ? req.query.token : '';
|
|
91
|
+
if (!token) {
|
|
92
|
+
res.status(400).json({ success: false, error: 'Missing token.' });
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
// API callers must POST — GET never redeems.
|
|
96
|
+
if (req.query.format === 'json') {
|
|
97
|
+
res.status(405).json({ success: false, error: 'Redemption requires POST.', method: 'POST', path: `${MAGIC_LINK_MOUNT_PATH}/redeem` });
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
res
|
|
101
|
+
.status(200)
|
|
102
|
+
.type('html')
|
|
103
|
+
.send(buildRedeemLandingHtml(token, `${MAGIC_LINK_MOUNT_PATH}/redeem`));
|
|
104
|
+
});
|
|
105
|
+
// POST /redeem performs the actual (side-effectful) redemption. Token arrives
|
|
106
|
+
// from the interstitial form body, an API client's JSON body, or the query.
|
|
107
|
+
publicRouter.post('/redeem', redeemLimiter, urlencoded({ extended: false }), json(), async (req, res) => {
|
|
108
|
+
const body = (req.body ?? {});
|
|
109
|
+
const token = (typeof body.token === 'string' && body.token) ||
|
|
110
|
+
(typeof req.query.token === 'string' ? req.query.token : '');
|
|
111
|
+
const wantsJson = req.query.format === 'json' || req.is('application/json') === 'application/json';
|
|
112
|
+
if (!token) {
|
|
113
|
+
res.status(400).json({ success: false, error: 'Missing token.' });
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
// Forensic context for the redemption audit trail. `req.ip` honors the app's
|
|
117
|
+
// trust-proxy setting; headers are best-effort and may be absent for API clients.
|
|
118
|
+
const result = await service.RedeemInvite(token, {
|
|
119
|
+
ipAddress: req.ip,
|
|
120
|
+
userAgent: req.get('user-agent') ?? undefined,
|
|
121
|
+
origin: req.get('origin') ?? undefined,
|
|
122
|
+
});
|
|
123
|
+
sendRedeemResult(res, result, wantsJson);
|
|
124
|
+
});
|
|
125
|
+
// ── Authenticated (invite creation) ───────────────────────────────────────
|
|
126
|
+
const authenticatedRouter = Router();
|
|
127
|
+
authenticatedRouter.post('/create', createLimiter, json(), async (req, res) => {
|
|
128
|
+
const creatingUser = req.userPayload?.userRecord;
|
|
129
|
+
if (!creatingUser) {
|
|
130
|
+
res.status(401).json({ success: false, error: 'Authentication required.' });
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
const body = (req.body ?? {});
|
|
134
|
+
if (!body.email || !body.applicationId) {
|
|
135
|
+
res.status(400).json({ success: false, error: 'email and applicationId are required.' });
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
const result = await service.CreateInvite({
|
|
139
|
+
email: body.email,
|
|
140
|
+
applicationId: body.applicationId,
|
|
141
|
+
roleId: body.roleId,
|
|
142
|
+
expiresInHours: body.expiresInHours,
|
|
143
|
+
maxUses: body.maxUses,
|
|
144
|
+
firstName: body.firstName,
|
|
145
|
+
lastName: body.lastName,
|
|
146
|
+
}, creatingUser);
|
|
147
|
+
// forbidden → 403 (caller not allowed to issue invites); invalid_role and
|
|
148
|
+
// other validation failures → 400.
|
|
149
|
+
const status = result.success ? 200 : result.errorCode === 'forbidden' ? 403 : 400;
|
|
150
|
+
res.status(status).json(result);
|
|
151
|
+
});
|
|
152
|
+
return { publicRouter, authenticatedRouter };
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Registers the `magic-link` auth provider so MJServer's issuer-driven JWT
|
|
156
|
+
* validation accepts MJ-issued session tokens. Issuer = public URL, JWKS URL =
|
|
157
|
+
* the public JWKS endpoint, audience = configured magic-link audience.
|
|
158
|
+
*
|
|
159
|
+
* Also appends the provider to `configInfo.authProviders` so a later
|
|
160
|
+
* `initializeAuthProviders()` (which clears + repopulates from config) keeps it.
|
|
161
|
+
*/
|
|
162
|
+
export function registerMagicLinkAuthProvider(publicUrl, config) {
|
|
163
|
+
const base = publicUrl.replace(/\/$/, '');
|
|
164
|
+
const providerConfig = {
|
|
165
|
+
name: 'magic-link',
|
|
166
|
+
type: 'magic-link',
|
|
167
|
+
issuer: publicUrl,
|
|
168
|
+
audience: config.audience,
|
|
169
|
+
jwksUri: `${base}${MAGIC_LINK_JWKS_PATH}`,
|
|
170
|
+
};
|
|
171
|
+
try {
|
|
172
|
+
configInfo.authProviders = configInfo.authProviders ?? [];
|
|
173
|
+
if (!configInfo.authProviders.some((p) => p.type === 'magic-link')) {
|
|
174
|
+
configInfo.authProviders.push(providerConfig);
|
|
175
|
+
}
|
|
176
|
+
const factory = AuthProviderFactory.Instance;
|
|
177
|
+
factory.register(AuthProviderFactory.createProvider(providerConfig));
|
|
178
|
+
LogStatus(`[MagicLink] Registered auth provider (issuer: ${publicUrl}, jwks: ${providerConfig.jwksUri})`);
|
|
179
|
+
}
|
|
180
|
+
catch (e) {
|
|
181
|
+
LogError(`[MagicLink] Failed to register auth provider: ${e instanceof Error ? e.message : String(e)}`);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
//# sourceMappingURL=MagicLinkRouter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MagicLinkRouter.js","sourceRoot":"","sources":["../../../src/auth/magicLink/MagicLinkRouter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Imperative shell for magic links: invite creation, redemption,
|
|
3
|
+
* user provisioning, and session-token minting. The pure logic lives in
|
|
4
|
+
* `magicLinkCore.ts`; this module wires it to the DB, key manager, and
|
|
5
|
+
* communication engine.
|
|
6
|
+
*
|
|
7
|
+
* @module @memberjunction/server/auth/magicLink
|
|
8
|
+
*/
|
|
9
|
+
import { UserInfo, type IMetadataProvider } from '@memberjunction/core';
|
|
10
|
+
import { type MagicLinkConfig } from '../../config.js';
|
|
11
|
+
import type { CreateMagicLinkInviteParams, CreateMagicLinkInviteResult, RedeemMagicLinkResult, RedeemAuditContext } from './types.js';
|
|
12
|
+
/**
|
|
13
|
+
* Magic-link service. One instance per server, constructed with the resolved
|
|
14
|
+
* public URL and the validated config.
|
|
15
|
+
*/
|
|
16
|
+
export declare class MagicLinkService {
|
|
17
|
+
private readonly publicUrl;
|
|
18
|
+
private readonly config;
|
|
19
|
+
constructor(publicUrl: string, config: MagicLinkConfig);
|
|
20
|
+
/**
|
|
21
|
+
* Creates a single-use, app-scoped invite, persists its hashed token, and
|
|
22
|
+
* (when a communication provider is configured) emails the link.
|
|
23
|
+
*
|
|
24
|
+
* @param params invite parameters
|
|
25
|
+
* @param creatingUser the authenticated internal user issuing the invite
|
|
26
|
+
* @param provider the request's metadata provider; falls back to the global default
|
|
27
|
+
*/
|
|
28
|
+
CreateInvite(params: CreateMagicLinkInviteParams, creatingUser: UserInfo, provider?: IMetadataProvider): Promise<CreateMagicLinkInviteResult>;
|
|
29
|
+
/**
|
|
30
|
+
* Redeems a raw token: validates the invite, atomically consumes one use,
|
|
31
|
+
* provisions/links the user with the restricted role + app, and mints a
|
|
32
|
+
* session JWT. Runs in the public (pre-auth) path, so it uses the global
|
|
33
|
+
* provider and a configured provisioning context user.
|
|
34
|
+
*
|
|
35
|
+
* Single-use is enforced by a compare-and-swap UPDATE ({@link consumeInvite})
|
|
36
|
+
* BEFORE the token is minted — two concurrent redemptions of a single-use
|
|
37
|
+
* link race on the same row and exactly one wins. The consume is the gate:
|
|
38
|
+
* if a later step fails, the use is already burned (fail-closed). That is the
|
|
39
|
+
* correct trade-off for a single-use credential — burning a token on a server
|
|
40
|
+
* error is recoverable (re-issue); allowing replay is not.
|
|
41
|
+
*/
|
|
42
|
+
RedeemInvite(rawToken: string, audit?: RedeemAuditContext): Promise<RedeemMagicLinkResult>;
|
|
43
|
+
/**
|
|
44
|
+
* Writes one MagicLinkRedemption audit row for a redemption attempt. Best-effort:
|
|
45
|
+
* a failure here is logged but never fails the redemption (the user already has,
|
|
46
|
+
* or has been denied, their session — losing an audit row must not change that).
|
|
47
|
+
*
|
|
48
|
+
* InviteID/ProvisionedUserID are null when the attempt didn't get far enough to
|
|
49
|
+
* resolve them (e.g. a malformed or unknown token — exactly the scan/brute-force
|
|
50
|
+
* signal we want recorded). IP/User-Agent/Origin are stored as supplied by the
|
|
51
|
+
* router per the deployment's audit policy.
|
|
52
|
+
*/
|
|
53
|
+
private recordRedemption;
|
|
54
|
+
/**
|
|
55
|
+
* Writes the Phase-2 multi-scope child rows (one application + one role) that
|
|
56
|
+
* mirror the invite's single ApplicationID/RoleID. The columns remain the
|
|
57
|
+
* source of truth for redemption today; these rows pre-stage the data for the
|
|
58
|
+
* eventual switch to multi-scope reads, avoiding a breaking migration later.
|
|
59
|
+
* Best-effort: a child-write failure is logged but does not fail invite
|
|
60
|
+
* issuance (the columns alone keep the one-of-each flow working).
|
|
61
|
+
*/
|
|
62
|
+
private writeInviteScopeChildRows;
|
|
63
|
+
/** Resolves the configured restricted role's ID, if present. */
|
|
64
|
+
private resolveRestrictedRoleId;
|
|
65
|
+
/** Builds the shareable redemption URL. */
|
|
66
|
+
private buildRedemptionUrl;
|
|
67
|
+
/**
|
|
68
|
+
* Provisions the redeeming user: finds them by email or creates them, then
|
|
69
|
+
* ensures the restricted role and the single app assignment exist.
|
|
70
|
+
*/
|
|
71
|
+
private provisionUser;
|
|
72
|
+
/**
|
|
73
|
+
* Resolves the shared Anonymous principal for an anonymous-mode redemption. This
|
|
74
|
+
* principal is an ATTRIBUTION ANCHOR only — it holds no scenario roles and gets no
|
|
75
|
+
* UserRole/UserApplication rows here, so concurrent anon visitors can never accrete
|
|
76
|
+
* scope onto a shared identity. Their actual scope lives in the per-session JWT
|
|
77
|
+
* claims (mj_scopes) and is enforced claims-side. Fail-closed if the principal was
|
|
78
|
+
* never seeded (the Phase-4 migration is required).
|
|
79
|
+
*/
|
|
80
|
+
private resolveAnonymousPrincipal;
|
|
81
|
+
/**
|
|
82
|
+
* True if an existing account is "protected" from magic-link provisioning: an
|
|
83
|
+
* Owner, or a user holding any role OUTSIDE the set of roles magic-link may
|
|
84
|
+
* legitimately grant. That allowed set is: the configured restricted role, the
|
|
85
|
+
* deployment's `grantableRoleNames`, AND the role THIS invite grants. So a prior
|
|
86
|
+
* magic-link guest holding only magic-link-grantable roles (e.g. the invite's own
|
|
87
|
+
* granted role) is NOT protected — re-redeeming a multi-use link is the intended
|
|
88
|
+
* flow. A user holding e.g. Developer/Admin is still protected and blocked.
|
|
89
|
+
*
|
|
90
|
+
* @param user the existing account being re-provisioned
|
|
91
|
+
* @param invitedRoleName the role name this invite grants
|
|
92
|
+
*/
|
|
93
|
+
private isProtectedAccount;
|
|
94
|
+
/** Creates a new user with exactly the restricted role + single app, transactionally. */
|
|
95
|
+
private createScopedUser;
|
|
96
|
+
/** Idempotently ensures an existing user has the given role and app assignment. */
|
|
97
|
+
private ensureRoleAndApp;
|
|
98
|
+
/** Idempotently ensures the role has CanAccess to the application (Application Role). */
|
|
99
|
+
private ensureAppAccess;
|
|
100
|
+
/**
|
|
101
|
+
* Atomically consumes one use of the invite via a compare-and-swap UPDATE.
|
|
102
|
+
* The WHERE clause re-checks every eligibility condition (Active, not
|
|
103
|
+
* exhausted, not expired) at the DB level, so the increment and the guard are
|
|
104
|
+
* a single atomic operation. Returns true ONLY when this call updated the row
|
|
105
|
+
* (won the race); concurrent redemptions of a single-use link see 0 rows.
|
|
106
|
+
*
|
|
107
|
+
* Fail-closed: any DB error returns false and the redemption is rejected.
|
|
108
|
+
*/
|
|
109
|
+
private consumeInvite;
|
|
110
|
+
/** Pushes a freshly created user into the UserCache with its single role. */
|
|
111
|
+
private pushUserToCache;
|
|
112
|
+
/**
|
|
113
|
+
* True iff the invite's creator resolves to a still-active user. Used to
|
|
114
|
+
* fail-closed at redeem time so a deactivated/removed inviter's outstanding
|
|
115
|
+
* links stop working. A missing/blank CreatedByUserID is treated as inactive.
|
|
116
|
+
*/
|
|
117
|
+
private isInviterActive;
|
|
118
|
+
/** Resolves the user whose context provisions magic-link users. */
|
|
119
|
+
private resolveProvisioningContextUser;
|
|
120
|
+
/** Sends the invite email via the configured communication provider. Best-effort. */
|
|
121
|
+
private sendInviteEmail;
|
|
122
|
+
}
|
|
123
|
+
//# sourceMappingURL=MagicLinkService.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MagicLinkService.d.ts","sourceRoot":"","sources":["../../../src/auth/magicLink/MagicLinkService.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAGL,QAAQ,EAIR,KAAK,iBAAiB,EAEvB,MAAM,sBAAsB,CAAC;AAgB9B,OAAO,EAAc,KAAK,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAGnE,OAAO,KAAK,EACV,2BAA2B,EAC3B,2BAA2B,EAC3B,qBAAqB,EACrB,kBAAkB,EACnB,MAAM,YAAY,CAAC;AAkBpB;;;GAGG;AACH,qBAAa,gBAAgB;IAEzB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,MAAM;gBADN,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,eAAe;IAG1C;;;;;;;OAOG;IACU,YAAY,CACvB,MAAM,EAAE,2BAA2B,EACnC,YAAY,EAAE,QAAQ,EACtB,QAAQ,CAAC,EAAE,iBAAiB,GAC3B,OAAO,CAAC,2BAA2B,CAAC;IAsFvC;;;;;;;;;;;;OAYG;IACU,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,qBAAqB,CAAC;IAmIvG;;;;;;;;;OASG;YACW,gBAAgB;IAoC9B;;;;;;;OAOG;YACW,yBAAyB;IA4BvC,gEAAgE;IAChE,OAAO,CAAC,uBAAuB;IAM/B,2CAA2C;IAC3C,OAAO,CAAC,kBAAkB;IAK1B;;;OAGG;YACW,aAAa;IAgD3B;;;;;;;OAOG;IACH,OAAO,CAAC,yBAAyB;IASjC;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,kBAAkB;IAY1B,yFAAyF;YAC3E,gBAAgB;IA2D9B,mFAAmF;YACrE,gBAAgB;IA4C9B,yFAAyF;YAC3E,eAAe;IA6B7B;;;;;;;;OAQG;YACW,aAAa;IAkB3B,6EAA6E;IAC7E,OAAO,CAAC,eAAe;IAOvB;;;;OAIG;IACH,OAAO,CAAC,eAAe;IAQvB,mEAAmE;IACnE,OAAO,CAAC,8BAA8B;IAYtC,qFAAqF;YACvE,eAAe;CA0B9B"}
|