@flink-app/oidc-plugin 2.0.0-alpha.116 → 2.0.0-alpha.118
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/CHANGELOG.md +55 -0
- package/README.md +296 -17
- package/dist/OidcPlugin.d.ts.map +1 -1
- package/dist/OidcPlugin.js +35 -2
- package/dist/OidcPluginContext.d.ts +17 -0
- package/dist/OidcPluginContext.d.ts.map +1 -1
- package/dist/OidcPluginOptions.d.ts +123 -3
- package/dist/OidcPluginOptions.d.ts.map +1 -1
- package/dist/handlers/CallbackOidc.d.ts.map +1 -1
- package/dist/handlers/CallbackOidc.js +97 -20
- package/dist/handlers/InitiateOidc.d.ts.map +1 -1
- package/dist/handlers/InitiateOidc.js +12 -3
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -1
- package/dist/providers/ProviderRegistry.d.ts +27 -4
- package/dist/providers/ProviderRegistry.d.ts.map +1 -1
- package/dist/providers/ProviderRegistry.js +77 -21
- package/dist/utils/error-utils.d.ts +1 -0
- package/dist/utils/error-utils.d.ts.map +1 -1
- package/dist/utils/error-utils.js +1 -0
- package/dist/utils/redirect-uri-utils.d.ts +38 -0
- package/dist/utils/redirect-uri-utils.d.ts.map +1 -0
- package/dist/utils/redirect-uri-utils.js +92 -0
- package/examples/basic-oidc.ts +4 -0
- package/examples/multi-provider.ts +4 -0
- package/package.json +6 -6
- package/spec/handlers/CallbackOidc.spec.ts +330 -0
- package/spec/handlers/InitiateOidc.spec.ts +95 -1
- package/spec/helpers/test-helpers.ts +68 -0
- package/spec/plugin/OidcPlugin.spec.ts +165 -0
- package/spec/providers/ProviderRegistry.spec.ts +142 -0
- package/spec/utils/redirect-uri-utils.spec.ts +98 -0
- package/src/OidcPlugin.ts +38 -1
- package/src/OidcPluginContext.ts +18 -0
- package/src/OidcPluginOptions.ts +132 -3
- package/src/handlers/CallbackOidc.ts +109 -20
- package/src/handlers/InitiateOidc.ts +14 -3
- package/src/index.ts +10 -1
- package/src/providers/ProviderRegistry.ts +95 -22
- package/src/utils/error-utils.ts +1 -0
- package/src/utils/redirect-uri-utils.ts +116 -0
|
@@ -4,31 +4,39 @@ exports.ProviderRegistry = void 0;
|
|
|
4
4
|
const OidcProvider_1 = require("./OidcProvider");
|
|
5
5
|
const error_utils_1 = require("../utils/error-utils");
|
|
6
6
|
const log_1 = require("../log");
|
|
7
|
+
const flink_1 = require("@flink-app/flink");
|
|
7
8
|
/**
|
|
8
9
|
* Provider registry for managing OIDC provider instances
|
|
9
10
|
*
|
|
10
11
|
* Handles:
|
|
11
12
|
* - Static provider configuration
|
|
12
13
|
* - Dynamic provider loading from database
|
|
13
|
-
* - Provider instance caching
|
|
14
|
+
* - Provider instance caching (optionally with a TTL)
|
|
14
15
|
* - Lazy initialization
|
|
15
16
|
*/
|
|
16
17
|
class ProviderRegistry {
|
|
17
|
-
constructor(staticProviders, providerLoader, ctx) {
|
|
18
|
+
constructor(staticProviders, providerLoader, ctx, providerCacheTtlSec = 0) {
|
|
18
19
|
this.providerInstances = new Map();
|
|
19
20
|
this.staticProviders = staticProviders;
|
|
20
21
|
this.providerLoader = providerLoader;
|
|
21
22
|
this.ctx = ctx;
|
|
23
|
+
this.providerCacheTtlSec = providerCacheTtlSec;
|
|
22
24
|
}
|
|
23
25
|
/**
|
|
24
26
|
* Get provider instance by name
|
|
25
27
|
*
|
|
26
28
|
* Looks up provider in the following order:
|
|
27
|
-
* 1. Cached instance
|
|
29
|
+
* 1. Cached instance (unless it is older than `providerCacheTtlSec`)
|
|
28
30
|
* 2. Static configuration
|
|
29
31
|
* 3. Dynamic loader (if configured)
|
|
30
32
|
*
|
|
31
|
-
* Providers are lazy-initialized on first use and cached.
|
|
33
|
+
* Providers are lazy-initialized on first use and cached. With a cache TTL
|
|
34
|
+
* configured, an expired entry is reloaded on the next request — the config is
|
|
35
|
+
* resolved again (re-running `providerLoader`) and discovery is re-run.
|
|
36
|
+
*
|
|
37
|
+
* If reloading an expired entry fails, the previous instance keeps being used: a
|
|
38
|
+
* transient discovery or database hiccup should not break logins that would
|
|
39
|
+
* otherwise work. The next reload attempt happens after another TTL.
|
|
32
40
|
*
|
|
33
41
|
* @param providerName - Provider identifier
|
|
34
42
|
* @returns Initialized OIDC provider instance
|
|
@@ -36,34 +44,80 @@ class ProviderRegistry {
|
|
|
36
44
|
*/
|
|
37
45
|
async getProvider(providerName) {
|
|
38
46
|
// Check cache first
|
|
39
|
-
const
|
|
40
|
-
if (
|
|
47
|
+
const cached = this.providerInstances.get(providerName);
|
|
48
|
+
if (cached && !this.isExpired(cached)) {
|
|
41
49
|
log_1.oidcLog.debug(`Provider "${providerName}": using cached instance`);
|
|
42
|
-
return
|
|
50
|
+
return cached.provider;
|
|
43
51
|
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
//
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
config = await this.
|
|
51
|
-
|
|
52
|
+
if (cached) {
|
|
53
|
+
log_1.oidcLog.debug(`Provider "${providerName}": cache entry older than ${this.providerCacheTtlSec}s, reloading`);
|
|
54
|
+
}
|
|
55
|
+
// Resolve config (static config first, then the dynamic loader)
|
|
56
|
+
let config;
|
|
57
|
+
try {
|
|
58
|
+
config = await this.resolveConfig(providerName);
|
|
59
|
+
}
|
|
60
|
+
catch (error) {
|
|
61
|
+
return this.keepCachedOnFailure(providerName, cached, "config could not be loaded", error);
|
|
52
62
|
}
|
|
53
63
|
if (!config) {
|
|
64
|
+
// Provider is genuinely gone (or never existed) — drop any cached instance
|
|
65
|
+
this.providerInstances.delete(providerName);
|
|
54
66
|
log_1.oidcLog.debug(`Provider "${providerName}": not found (static=[${Object.keys(this.staticProviders).join(", ")}], loader=${!!this.providerLoader})`);
|
|
55
67
|
throw (0, error_utils_1.createOidcError)(error_utils_1.OidcErrorCodes.PROVIDER_NOT_CONFIGURED, `OIDC provider '${providerName}' is not configured`, {
|
|
56
68
|
providerName,
|
|
57
69
|
availableProviders: Object.keys(this.staticProviders),
|
|
58
70
|
});
|
|
59
71
|
}
|
|
60
|
-
log_1.oidcLog.debug(`Provider "${providerName}" resolved via ${
|
|
72
|
+
log_1.oidcLog.debug(`Provider "${providerName}" resolved via ${providerName in this.staticProviders ? "static" : "dynamic"}:`, `issuer=${config.issuer}`, `clientId=${config.clientId}`, `clientSecret=${(0, log_1.maskSecret)(config.clientSecret)}`, `callbackUrl=${config.callbackUrl}`, config.discoveryUrl ? `discoveryUrl=${config.discoveryUrl}` : `authorizationEndpoint=${config.authorizationEndpoint}`, `scope=${(config.scope || ["openid", "email", "profile"]).join(" ")}`);
|
|
61
73
|
// Create and initialize provider
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
74
|
+
try {
|
|
75
|
+
const provider = new OidcProvider_1.OidcProvider(config);
|
|
76
|
+
await provider.initialize();
|
|
77
|
+
// Cache the instance
|
|
78
|
+
this.providerInstances.set(providerName, { provider, loadedAt: Date.now() });
|
|
79
|
+
return provider;
|
|
80
|
+
}
|
|
81
|
+
catch (error) {
|
|
82
|
+
return this.keepCachedOnFailure(providerName, cached, "initialization failed", error);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Resolve provider config from static configuration or the dynamic loader
|
|
87
|
+
*/
|
|
88
|
+
async resolveConfig(providerName) {
|
|
89
|
+
const staticConfig = this.staticProviders[providerName];
|
|
90
|
+
if (staticConfig) {
|
|
91
|
+
return staticConfig;
|
|
92
|
+
}
|
|
93
|
+
if (this.providerLoader) {
|
|
94
|
+
log_1.oidcLog.debug(`Provider "${providerName}": not in static config, invoking providerLoader`);
|
|
95
|
+
return await this.providerLoader(providerName, this.ctx);
|
|
96
|
+
}
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Whether a cache entry has outlived the configured TTL.
|
|
101
|
+
* A TTL of 0 (the default) means entries are cached for the life of the process.
|
|
102
|
+
*/
|
|
103
|
+
isExpired(cached) {
|
|
104
|
+
if (this.providerCacheTtlSec <= 0) {
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
107
|
+
return Date.now() - cached.loadedAt >= this.providerCacheTtlSec * 1000;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Keep serving a previously cached instance when a reload fails.
|
|
111
|
+
* Rethrows when there is nothing cached to fall back on.
|
|
112
|
+
*/
|
|
113
|
+
keepCachedOnFailure(providerName, cached, reason, error) {
|
|
114
|
+
if (!cached) {
|
|
115
|
+
throw error;
|
|
116
|
+
}
|
|
117
|
+
flink_1.log.warn(`OIDC Plugin: reload of provider "${providerName}" failed (${reason}), keeping the previously cached instance: ${error.message}`);
|
|
118
|
+
// Restart the TTL window so a persistent failure is not retried on every request
|
|
119
|
+
cached.loadedAt = Date.now();
|
|
120
|
+
return cached.provider;
|
|
67
121
|
}
|
|
68
122
|
/**
|
|
69
123
|
* Check if provider exists in static configuration or can be loaded dynamically
|
|
@@ -80,6 +134,8 @@ class ProviderRegistry {
|
|
|
80
134
|
* Forces re-initialization of providers on next access.
|
|
81
135
|
* Useful when provider configurations change.
|
|
82
136
|
*
|
|
137
|
+
* Exposed to applications as `ctx.plugins.oidc.invalidateProvider()`.
|
|
138
|
+
*
|
|
83
139
|
* @param providerName - Optional provider to clear (clears all if not specified)
|
|
84
140
|
*/
|
|
85
141
|
clearCache(providerName) {
|
|
@@ -10,6 +10,7 @@ export declare const OidcErrorCodes: {
|
|
|
10
10
|
readonly MISSING_STATE: "missing_state";
|
|
11
11
|
readonly INVALID_STATE: "invalid_state";
|
|
12
12
|
readonly INVALID_RESPONSE_TYPE: "invalid_response_type";
|
|
13
|
+
readonly INVALID_REDIRECT_URI: "invalid_redirect_uri";
|
|
13
14
|
readonly SESSION_NOT_FOUND: "session_not_found";
|
|
14
15
|
readonly SESSION_EXPIRED: "session_expired";
|
|
15
16
|
readonly TOKEN_EXCHANGE_FAILED: "token_exchange_failed";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"error-utils.d.ts","sourceRoot":"","sources":["../../src/utils/error-utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAEjD;;GAEG;AACH,eAAO,MAAM,cAAc
|
|
1
|
+
{"version":3,"file":"error-utils.d.ts","sourceRoot":"","sources":["../../src/utils/error-utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAEjD;;GAEG;AACH,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;CAqCjB,CAAC;AAEX;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,GAAG,SAAS,CAgBvF;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CASvD;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAMhE;AAED;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,GAAG,GAAG,SAAS,CAsDzD"}
|
|
@@ -18,6 +18,7 @@ exports.OidcErrorCodes = {
|
|
|
18
18
|
MISSING_STATE: "missing_state",
|
|
19
19
|
INVALID_STATE: "invalid_state",
|
|
20
20
|
INVALID_RESPONSE_TYPE: "invalid_response_type",
|
|
21
|
+
INVALID_REDIRECT_URI: "invalid_redirect_uri",
|
|
21
22
|
// Session errors
|
|
22
23
|
SESSION_NOT_FOUND: "session_not_found",
|
|
23
24
|
SESSION_EXPIRED: "session_expired",
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Redirect URI allow-list utilities
|
|
3
|
+
*
|
|
4
|
+
* The `?redirectUri=` query parameter on `/oidc/:provider/initiate` decides where the
|
|
5
|
+
* host's JWT is delivered once the OIDC flow completes. It is attacker-controllable —
|
|
6
|
+
* anyone can craft an initiate link — so deployments should restrict it to the URLs
|
|
7
|
+
* their own clients use via the `allowedRedirectUris` plugin option.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Allow-list for the `redirectUri` query parameter.
|
|
11
|
+
*
|
|
12
|
+
* Either a list of entries or a predicate:
|
|
13
|
+
* - An entry that is a bare origin (`https://app.example.com`, `myapp://cb`) matches any
|
|
14
|
+
* path/query/fragment below that origin.
|
|
15
|
+
* - An entry with a path (`https://app.example.com/login`) matches that exact URI only.
|
|
16
|
+
* - A predicate receives the requested redirectUri and the provider name.
|
|
17
|
+
*/
|
|
18
|
+
export type AllowedRedirectUris = string[] | ((redirectUri: string, provider: string) => boolean);
|
|
19
|
+
/**
|
|
20
|
+
* Whether a redirect target is a relative path on the plugin's own origin.
|
|
21
|
+
*
|
|
22
|
+
* `/dashboard` and `/login?error=x` are relative. `//evil.example` (protocol-relative)
|
|
23
|
+
* and `/\evil.example` are NOT — browsers resolve both of those to another origin.
|
|
24
|
+
*/
|
|
25
|
+
export declare function isRelativeRedirect(redirectUri: string): boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Check whether a redirect URI is allowed.
|
|
28
|
+
*
|
|
29
|
+
* @param redirectUri - The redirect target to check
|
|
30
|
+
* @param provider - Provider name (passed to the predicate form)
|
|
31
|
+
* @param allowedRedirectUris - The `allowedRedirectUris` plugin option. Undefined means
|
|
32
|
+
* no allow-list is configured and every URI is accepted (legacy behaviour).
|
|
33
|
+
* @param alwaysAllowed - Entries that bypass the allow-list, e.g. the provider's own
|
|
34
|
+
* `callbackUrl` and the redirectUri already validated at initiate time.
|
|
35
|
+
* @returns true if the redirect may be performed
|
|
36
|
+
*/
|
|
37
|
+
export declare function isRedirectUriAllowed(redirectUri: string, provider: string, allowedRedirectUris?: AllowedRedirectUris, alwaysAllowed?: (string | undefined)[]): boolean;
|
|
38
|
+
//# sourceMappingURL=redirect-uri-utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redirect-uri-utils.d.ts","sourceRoot":"","sources":["../../src/utils/redirect-uri-utils.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH;;;;;;;;GAQG;AACH,MAAM,MAAM,mBAAmB,GAAG,MAAM,EAAE,GAAG,CAAC,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,CAAC;AAElG;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAE/D;AAiDD;;;;;;;;;;GAUG;AACH,wBAAgB,oBAAoB,CAChC,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,EAChB,mBAAmB,CAAC,EAAE,mBAAmB,EACzC,aAAa,GAAE,CAAC,MAAM,GAAG,SAAS,CAAC,EAAO,GAC3C,OAAO,CAsBT"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Redirect URI allow-list utilities
|
|
4
|
+
*
|
|
5
|
+
* The `?redirectUri=` query parameter on `/oidc/:provider/initiate` decides where the
|
|
6
|
+
* host's JWT is delivered once the OIDC flow completes. It is attacker-controllable —
|
|
7
|
+
* anyone can craft an initiate link — so deployments should restrict it to the URLs
|
|
8
|
+
* their own clients use via the `allowedRedirectUris` plugin option.
|
|
9
|
+
*/
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.isRelativeRedirect = isRelativeRedirect;
|
|
12
|
+
exports.isRedirectUriAllowed = isRedirectUriAllowed;
|
|
13
|
+
/**
|
|
14
|
+
* Whether a redirect target is a relative path on the plugin's own origin.
|
|
15
|
+
*
|
|
16
|
+
* `/dashboard` and `/login?error=x` are relative. `//evil.example` (protocol-relative)
|
|
17
|
+
* and `/\evil.example` are NOT — browsers resolve both of those to another origin.
|
|
18
|
+
*/
|
|
19
|
+
function isRelativeRedirect(redirectUri) {
|
|
20
|
+
return /^\/(?![/\\])/.test(redirectUri);
|
|
21
|
+
}
|
|
22
|
+
function parseUrl(value) {
|
|
23
|
+
try {
|
|
24
|
+
return new URL(value);
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return undefined;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Origin of a URL, including custom schemes.
|
|
32
|
+
* `URL.origin` is the string "null" for non-special schemes (e.g. `myapp://cb`),
|
|
33
|
+
* so fall back to scheme + host for those.
|
|
34
|
+
*/
|
|
35
|
+
function originOf(url) {
|
|
36
|
+
return url.origin && url.origin !== "null" ? url.origin : `${url.protocol}//${url.host}`;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Whether an allow-list entry names a bare origin (no path, query or fragment)
|
|
40
|
+
* and therefore matches every URI below that origin.
|
|
41
|
+
*/
|
|
42
|
+
function isOriginOnlyEntry(url) {
|
|
43
|
+
return (url.pathname === "" || url.pathname === "/") && !url.search && !url.hash;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Match a redirect URI against a single allow-list entry.
|
|
47
|
+
* Exact string match always wins; origin-only entries additionally match by origin.
|
|
48
|
+
*/
|
|
49
|
+
function matchesEntry(redirectUri, entry) {
|
|
50
|
+
if (redirectUri === entry) {
|
|
51
|
+
return true;
|
|
52
|
+
}
|
|
53
|
+
const entryUrl = parseUrl(entry);
|
|
54
|
+
if (!entryUrl || !isOriginOnlyEntry(entryUrl)) {
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
const targetUrl = parseUrl(redirectUri);
|
|
58
|
+
if (!targetUrl) {
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
return originOf(targetUrl) === originOf(entryUrl);
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Check whether a redirect URI is allowed.
|
|
65
|
+
*
|
|
66
|
+
* @param redirectUri - The redirect target to check
|
|
67
|
+
* @param provider - Provider name (passed to the predicate form)
|
|
68
|
+
* @param allowedRedirectUris - The `allowedRedirectUris` plugin option. Undefined means
|
|
69
|
+
* no allow-list is configured and every URI is accepted (legacy behaviour).
|
|
70
|
+
* @param alwaysAllowed - Entries that bypass the allow-list, e.g. the provider's own
|
|
71
|
+
* `callbackUrl` and the redirectUri already validated at initiate time.
|
|
72
|
+
* @returns true if the redirect may be performed
|
|
73
|
+
*/
|
|
74
|
+
function isRedirectUriAllowed(redirectUri, provider, allowedRedirectUris, alwaysAllowed = []) {
|
|
75
|
+
// No allow-list configured: unchanged (permissive) behaviour
|
|
76
|
+
if (allowedRedirectUris === undefined) {
|
|
77
|
+
return true;
|
|
78
|
+
}
|
|
79
|
+
// Relative paths can only land on the plugin's own origin
|
|
80
|
+
if (isRelativeRedirect(redirectUri)) {
|
|
81
|
+
return true;
|
|
82
|
+
}
|
|
83
|
+
for (const entry of alwaysAllowed) {
|
|
84
|
+
if (entry && matchesEntry(redirectUri, entry)) {
|
|
85
|
+
return true;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
if (typeof allowedRedirectUris === "function") {
|
|
89
|
+
return allowedRedirectUris(redirectUri, provider);
|
|
90
|
+
}
|
|
91
|
+
return allowedRedirectUris.some((entry) => matchesEntry(redirectUri, entry));
|
|
92
|
+
}
|
package/examples/basic-oidc.ts
CHANGED
|
@@ -69,6 +69,10 @@ async function start() {
|
|
|
69
69
|
},
|
|
70
70
|
},
|
|
71
71
|
|
|
72
|
+
// Restrict where the JWT may be delivered after login.
|
|
73
|
+
// Without this, any ?redirectUri= passed to /initiate is accepted.
|
|
74
|
+
allowedRedirectUris: ["http://localhost:3000"],
|
|
75
|
+
|
|
72
76
|
// Step 3: Implement JIT user provisioning
|
|
73
77
|
onAuthSuccess: async ({ profile, claims, provider }, ctx) => {
|
|
74
78
|
console.log("OIDC authentication successful");
|
|
@@ -64,6 +64,10 @@ async function start() {
|
|
|
64
64
|
},
|
|
65
65
|
},
|
|
66
66
|
|
|
67
|
+
// Restrict where the JWT may be delivered after login.
|
|
68
|
+
// Without this, any ?redirectUri= passed to /initiate is accepted.
|
|
69
|
+
allowedRedirectUris: ["https://myapp.com", "myapp://oidc-callback"],
|
|
70
|
+
|
|
67
71
|
onAuthSuccess: async ({ profile, claims, provider }, ctx) => {
|
|
68
72
|
// Try to find existing user by OIDC connection
|
|
69
73
|
let user = await ctx.repos.userRepo.getOne({
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flink-app/oidc-plugin",
|
|
3
|
-
"version": "2.0.0-alpha.
|
|
3
|
+
"version": "2.0.0-alpha.118",
|
|
4
4
|
"description": "Flink plugin for OIDC authentication with generic IdP support",
|
|
5
5
|
"author": "joel@frost.se",
|
|
6
6
|
"license": "MIT",
|
|
@@ -11,10 +11,10 @@
|
|
|
11
11
|
},
|
|
12
12
|
"dependencies": {
|
|
13
13
|
"openid-client": "^5.7.0",
|
|
14
|
-
"@flink-app/jwt-auth-plugin": "2.0.0-alpha.
|
|
14
|
+
"@flink-app/jwt-auth-plugin": "2.0.0-alpha.118"
|
|
15
15
|
},
|
|
16
16
|
"peerDependencies": {
|
|
17
|
-
"@flink-app/flink": ">=2.0.0-alpha.
|
|
17
|
+
"@flink-app/flink": ">=2.0.0-alpha.118",
|
|
18
18
|
"mongodb": "^6.15.0"
|
|
19
19
|
},
|
|
20
20
|
"peerDependenciesMeta": {
|
|
@@ -27,9 +27,9 @@
|
|
|
27
27
|
"@types/node": "22.13.10",
|
|
28
28
|
"ts-node": "^10.9.2",
|
|
29
29
|
"tsc-watch": "^4.2.9",
|
|
30
|
-
"@flink-app/
|
|
31
|
-
"@flink-app/
|
|
32
|
-
"@flink-app/test-utils": "2.0.0-alpha.
|
|
30
|
+
"@flink-app/flink": "2.0.0-alpha.118",
|
|
31
|
+
"@flink-app/jwt-auth-plugin": "2.0.0-alpha.118",
|
|
32
|
+
"@flink-app/test-utils": "2.0.0-alpha.118"
|
|
33
33
|
},
|
|
34
34
|
"scripts": {
|
|
35
35
|
"test": "jasmine-ts --config=./spec/support/jasmine.json",
|