@naylence/runtime 0.3.5-test.910 → 0.3.5-test.913

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 (47) hide show
  1. package/dist/browser/index.cjs +1915 -1214
  2. package/dist/browser/index.mjs +1910 -1209
  3. package/dist/cjs/naylence/fame/config/extended-fame-config.js +52 -0
  4. package/dist/cjs/naylence/fame/factory-manifest.js +2 -0
  5. package/dist/cjs/naylence/fame/http/jwks-api-router.js +16 -18
  6. package/dist/cjs/naylence/fame/http/oauth2-server.js +28 -31
  7. package/dist/cjs/naylence/fame/http/oauth2-token-router.js +901 -93
  8. package/dist/cjs/naylence/fame/http/openid-configuration-router.js +30 -32
  9. package/dist/cjs/naylence/fame/node/admission/admission-profile-factory.js +79 -0
  10. package/dist/cjs/naylence/fame/security/auth/oauth2-pkce-token-provider-factory.js +171 -0
  11. package/dist/cjs/naylence/fame/security/auth/oauth2-pkce-token-provider.js +560 -0
  12. package/dist/cjs/naylence/fame/security/crypto/providers/default-crypto-provider.js +0 -162
  13. package/dist/cjs/naylence/fame/telemetry/open-telemetry-trace-emitter-factory.js +19 -2
  14. package/dist/cjs/naylence/fame/telemetry/open-telemetry-trace-emitter.js +19 -9
  15. package/dist/cjs/naylence/fame/util/register-runtime-factories.js +6 -0
  16. package/dist/cjs/version.js +2 -2
  17. package/dist/esm/naylence/fame/config/extended-fame-config.js +52 -0
  18. package/dist/esm/naylence/fame/factory-manifest.js +2 -0
  19. package/dist/esm/naylence/fame/http/jwks-api-router.js +16 -17
  20. package/dist/esm/naylence/fame/http/oauth2-server.js +28 -31
  21. package/dist/esm/naylence/fame/http/oauth2-token-router.js +901 -93
  22. package/dist/esm/naylence/fame/http/openid-configuration-router.js +30 -31
  23. package/dist/esm/naylence/fame/node/admission/admission-profile-factory.js +79 -0
  24. package/dist/esm/naylence/fame/security/auth/oauth2-pkce-token-provider-factory.js +134 -0
  25. package/dist/esm/naylence/fame/security/auth/oauth2-pkce-token-provider.js +555 -0
  26. package/dist/esm/naylence/fame/security/crypto/providers/default-crypto-provider.js +0 -162
  27. package/dist/esm/naylence/fame/telemetry/open-telemetry-trace-emitter-factory.js +19 -2
  28. package/dist/esm/naylence/fame/telemetry/open-telemetry-trace-emitter.js +19 -9
  29. package/dist/esm/naylence/fame/util/register-runtime-factories.js +6 -0
  30. package/dist/esm/version.js +2 -2
  31. package/dist/node/index.cjs +1911 -1210
  32. package/dist/node/index.mjs +1910 -1209
  33. package/dist/node/node.cjs +2945 -1439
  34. package/dist/node/node.mjs +2944 -1438
  35. package/dist/types/naylence/fame/factory-manifest.d.ts +1 -1
  36. package/dist/types/naylence/fame/http/jwks-api-router.d.ts +8 -8
  37. package/dist/types/naylence/fame/http/oauth2-server.d.ts +3 -3
  38. package/dist/types/naylence/fame/http/oauth2-token-router.d.ts +75 -19
  39. package/dist/types/naylence/fame/http/openid-configuration-router.d.ts +8 -8
  40. package/dist/types/naylence/fame/security/auth/oauth2-pkce-token-provider-factory.d.ts +27 -0
  41. package/dist/types/naylence/fame/security/auth/oauth2-pkce-token-provider.d.ts +42 -0
  42. package/dist/types/naylence/fame/security/crypto/providers/default-crypto-provider.d.ts +0 -1
  43. package/dist/types/naylence/fame/telemetry/open-telemetry-trace-emitter.d.ts +4 -0
  44. package/dist/types/version.d.ts +1 -1
  45. package/package.json +4 -4
  46. package/dist/esm/naylence/fame/fastapi/oauth2-server.js +0 -205
  47. package/dist/types/naylence/fame/fastapi/oauth2-server.d.ts +0 -22
@@ -1,9 +1,8 @@
1
1
  /**
2
- * OpenID Connect Discovery configuration router for Express
2
+ * OpenID Connect Discovery configuration plugin for Fastify
3
3
  *
4
4
  * Provides /.well-known/openid-configuration endpoint for OAuth2/OIDC client auto-discovery
5
5
  */
6
- import express from 'express';
7
6
  import { getLogger } from '../util/logging.js';
8
7
  const logger = getLogger('naylence.fame.http.openid_configuration_router');
9
8
  const DEFAULT_PREFIX = '';
@@ -77,10 +76,10 @@ function getAllowedScopes(configScopes) {
77
76
  return configScopes ?? ['node.connect'];
78
77
  }
79
78
  /**
80
- * Create an Express router that implements OpenID Connect Discovery
79
+ * Create a Fastify plugin that implements OpenID Connect Discovery
81
80
  *
82
81
  * @param options - Router configuration options
83
- * @returns Express router with OpenID configuration endpoint
82
+ * @returns Fastify plugin with OpenID configuration endpoint
84
83
  *
85
84
  * Environment Variables:
86
85
  * FAME_JWT_ISSUER: JWT issuer claim (optional)
@@ -89,17 +88,16 @@ function getAllowedScopes(configScopes) {
89
88
  *
90
89
  * @example
91
90
  * ```typescript
92
- * import express from 'express';
91
+ * import Fastify from 'fastify';
93
92
  * import { createOpenIDConfigurationRouter } from '@naylence/runtime';
94
93
  *
95
- * const app = express();
96
- * app.use(createOpenIDConfigurationRouter({
94
+ * const app = Fastify();
95
+ * app.register(createOpenIDConfigurationRouter({
97
96
  * issuer: 'https://auth.example.com',
98
97
  * }));
99
98
  * ```
100
99
  */
101
100
  export function createOpenIDConfigurationRouter(options = {}) {
102
- const router = express.Router();
103
101
  const { prefix = DEFAULT_PREFIX, issuer, baseUrl, tokenEndpointPath = '/oauth/token', jwksEndpointPath = '/.well-known/jwks.json', allowedScopes: configAllowedScopes, algorithm: configAlgorithm, } = normalizeOpenIDConfigurationRouterOptions(options);
104
102
  // Resolve configuration with environment variable priority
105
103
  const defaultIssuer = process.env[ENV_VAR_JWT_ISSUER] ?? issuer ?? 'https://auth.fame.fabric';
@@ -115,27 +113,28 @@ export function createOpenIDConfigurationRouter(options = {}) {
115
113
  algorithm,
116
114
  allowedScopes,
117
115
  });
118
- // OpenID Connect Discovery endpoint
119
- router.get(`${prefix}/.well-known/openid-configuration`, (_req, res) => {
120
- // Construct absolute URLs for endpoints
121
- const tokenEndpoint = `${defaultBaseUrl.replace(/\/$/, '')}${tokenEndpointPath}`;
122
- const jwksUri = `${defaultBaseUrl.replace(/\/$/, '')}${jwksEndpointPath}`;
123
- const config = {
124
- issuer: defaultIssuer,
125
- token_endpoint: tokenEndpoint,
126
- jwks_uri: jwksUri,
127
- scopes_supported: allowedScopes,
128
- response_types_supported: ['token'],
129
- grant_types_supported: ['client_credentials'],
130
- token_endpoint_auth_methods_supported: [
131
- 'client_secret_basic',
132
- 'client_secret_post',
133
- ],
134
- subject_types_supported: ['public'],
135
- id_token_signing_alg_values_supported: [algorithm],
136
- };
137
- logger.debug('openid_config_served', { config });
138
- res.json(config);
139
- });
140
- return router;
116
+ const plugin = async (instance) => {
117
+ instance.get(`${prefix}/.well-known/openid-configuration`, async (_request, reply) => {
118
+ // Construct absolute URLs for endpoints
119
+ const tokenEndpoint = `${defaultBaseUrl.replace(/\/$/, '')}${tokenEndpointPath}`;
120
+ const jwksUri = `${defaultBaseUrl.replace(/\/$/, '')}${jwksEndpointPath}`;
121
+ const config = {
122
+ issuer: defaultIssuer,
123
+ token_endpoint: tokenEndpoint,
124
+ jwks_uri: jwksUri,
125
+ scopes_supported: allowedScopes,
126
+ response_types_supported: ['token'],
127
+ grant_types_supported: ['client_credentials'],
128
+ token_endpoint_auth_methods_supported: [
129
+ 'client_secret_basic',
130
+ 'client_secret_post',
131
+ ],
132
+ subject_types_supported: ['public'],
133
+ id_token_signing_alg_values_supported: [algorithm],
134
+ };
135
+ logger.debug('openid_config_served', { config });
136
+ reply.send(config);
137
+ });
138
+ };
139
+ return plugin;
141
140
  }
@@ -8,18 +8,28 @@ const ENV_VAR_JWT_AUDIENCE = 'FAME_JWT_AUDIENCE';
8
8
  const ENV_VAR_ADMISSION_TOKEN_URL = 'FAME_ADMISSION_TOKEN_URL';
9
9
  const ENV_VAR_ADMISSION_CLIENT_ID = 'FAME_ADMISSION_CLIENT_ID';
10
10
  const ENV_VAR_ADMISSION_CLIENT_SECRET = 'FAME_ADMISSION_CLIENT_SECRET';
11
+ const ENV_VAR_ADMISSION_AUTHORIZE_URL = 'FAME_ADMISSION_AUTHORIZE_URL';
12
+ const ENV_VAR_ADMISSION_REDIRECT_URL = 'FAME_ADMISSION_REDIRECT_URL';
13
+ const ENV_VAR_ADMISSION_LOGIN_HINT_PARAM = 'FAME_ADMISSION_LOGIN_HINT_PARAM';
14
+ const ENV_VAR_ADMISSION_CODE_CHALLENGE_METHOD = 'FAME_ADMISSION_CODE_CHALLENGE_METHOD';
15
+ const ENV_VAR_ADMISSION_CODE_VERIFIER_LENGTH = 'FAME_ADMISSION_CODE_VERIFIER_LENGTH';
16
+ const ENV_VAR_ADMISSION_CLOCK_SKEW_SECONDS = 'FAME_ADMISSION_CLOCK_SKEW_SECONDS';
11
17
  const ENV_VAR_DIRECT_ADMISSION_URL = 'FAME_DIRECT_ADMISSION_URL';
12
18
  const ENV_VAR_DIRECT_INPAGE_CHANNEL = 'FAME_DIRECT_INPAGE_CHANNEL';
13
19
  const ENV_VAR_ADMISSION_SERVICE_URL = 'FAME_ADMISSION_SERVICE_URL';
14
20
  const DEFAULT_INPAGE_CHANNEL = 'naylence-fabric';
15
21
  const PROFILE_NAME_WELCOME = 'welcome';
22
+ const PROFILE_NAME_WELCOME_PKCE = 'welcome-pkce';
23
+ const PROFILE_NAME_WELCOME_PKCE_ALIAS = 'welcome_pkce';
16
24
  const PROFILE_NAME_DIRECT = 'direct';
17
25
  const PROFILE_NAME_DIRECT_HTTP = 'direct-http';
18
26
  const PROFILE_NAME_DIRECT_INPAGE = 'direct-inpage';
27
+ const PROFILE_NAME_DIRECT_PKCE = 'direct-pkce';
19
28
  const PROFILE_NAME_OPEN = 'open';
20
29
  const PROFILE_NAME_NOOP = 'noop';
21
30
  const PROFILE_NAME_NONE = 'none';
22
31
  const PROFILE_NAME_DIRECT_INPAGE_ALIAS = 'direct_inpage';
32
+ const PROFILE_NAME_DIRECT_PKCE_ALIAS = 'direct_pkce';
23
33
  function createOAuthTokenProviderConfig() {
24
34
  const tokenUrl = Expressions.env(ENV_VAR_ADMISSION_TOKEN_URL);
25
35
  const clientId = Expressions.env(ENV_VAR_ADMISSION_CLIENT_ID);
@@ -37,8 +47,41 @@ function createOAuthTokenProviderConfig() {
37
47
  audience,
38
48
  };
39
49
  }
50
+ function createOAuthPkceTokenProviderConfig() {
51
+ const authorizeUrl = Expressions.env(ENV_VAR_ADMISSION_AUTHORIZE_URL);
52
+ const tokenUrl = Expressions.env(ENV_VAR_ADMISSION_TOKEN_URL);
53
+ const redirectUri = Expressions.env(ENV_VAR_ADMISSION_REDIRECT_URL);
54
+ const clientId = Expressions.env(ENV_VAR_ADMISSION_CLIENT_ID);
55
+ const loginHintParam = Expressions.env(ENV_VAR_ADMISSION_LOGIN_HINT_PARAM, 'login_hint');
56
+ const audience = Expressions.env(ENV_VAR_JWT_AUDIENCE);
57
+ const codeChallengeMethod = Expressions.env(ENV_VAR_ADMISSION_CODE_CHALLENGE_METHOD, 'S256');
58
+ const codeVerifierLength = Expressions.env(ENV_VAR_ADMISSION_CODE_VERIFIER_LENGTH, '64');
59
+ const clockSkewSeconds = Expressions.env(ENV_VAR_ADMISSION_CLOCK_SKEW_SECONDS, '30');
60
+ return {
61
+ type: 'OAuth2PkceTokenProvider',
62
+ authorizeUrl,
63
+ authorize_url: authorizeUrl,
64
+ tokenUrl,
65
+ token_url: tokenUrl,
66
+ redirectUri,
67
+ redirect_uri: redirectUri,
68
+ clientId,
69
+ client_id: clientId,
70
+ loginHintParam,
71
+ login_hint_param: loginHintParam,
72
+ scopes: ['node.connect'],
73
+ audience,
74
+ codeChallengeMethod,
75
+ code_challenge_method: codeChallengeMethod,
76
+ codeVerifierLength,
77
+ code_verifier_length: codeVerifierLength,
78
+ clockSkewSeconds,
79
+ clock_skew_seconds: clockSkewSeconds,
80
+ };
81
+ }
40
82
  const welcomeIsRoot = Expressions.env(ENV_VAR_IS_ROOT, 'false');
41
83
  const welcomeTokenProvider = createOAuthTokenProviderConfig();
84
+ const welcomePkceTokenProvider = createOAuthPkceTokenProviderConfig();
42
85
  const WELCOME_SERVICE_PROFILE = {
43
86
  type: 'WelcomeServiceClient',
44
87
  is_root: welcomeIsRoot,
@@ -52,6 +95,19 @@ const WELCOME_SERVICE_PROFILE = {
52
95
  tokenProvider: welcomeTokenProvider,
53
96
  },
54
97
  };
98
+ const WELCOME_SERVICE_PKCE_PROFILE = {
99
+ type: 'WelcomeServiceClient',
100
+ is_root: welcomeIsRoot,
101
+ isRoot: welcomeIsRoot,
102
+ url: Expressions.env(ENV_VAR_ADMISSION_SERVICE_URL),
103
+ supported_transports: ['websocket'],
104
+ supportedTransports: ['websocket'],
105
+ auth: {
106
+ type: 'BearerTokenHeaderAuth',
107
+ token_provider: welcomePkceTokenProvider,
108
+ tokenProvider: welcomePkceTokenProvider,
109
+ },
110
+ };
55
111
  const directGrantTokenProvider = createOAuthTokenProviderConfig();
56
112
  const directGrant = {
57
113
  type: 'WebSocketConnectionGrant',
@@ -71,6 +127,25 @@ const DIRECT_PROFILE = {
71
127
  connection_grants: directGrants,
72
128
  connectionGrants: directGrants,
73
129
  };
130
+ const directPkceTokenProvider = createOAuthPkceTokenProviderConfig();
131
+ const directPkceGrant = {
132
+ type: 'WebSocketConnectionGrant',
133
+ purpose: GRANT_PURPOSE_NODE_ATTACH,
134
+ url: Expressions.env(ENV_VAR_DIRECT_ADMISSION_URL),
135
+ auth: {
136
+ type: 'WebSocketSubprotocolAuth',
137
+ token_provider: directPkceTokenProvider,
138
+ tokenProvider: directPkceTokenProvider,
139
+ },
140
+ ttl: 0,
141
+ durable: false,
142
+ };
143
+ const directPkceGrants = [directPkceGrant];
144
+ const DIRECT_PKCE_PROFILE = {
145
+ type: 'DirectAdmissionClient',
146
+ connection_grants: directPkceGrants,
147
+ connectionGrants: directPkceGrants,
148
+ };
74
149
  const directHttpTokenProvider = createOAuthTokenProviderConfig();
75
150
  const directHttpGrant = {
76
151
  type: 'HttpConnectionGrant',
@@ -138,7 +213,11 @@ const NOOP_PROFILE = {
138
213
  };
139
214
  const PROFILE_MAP = {
140
215
  [PROFILE_NAME_WELCOME]: WELCOME_SERVICE_PROFILE,
216
+ [PROFILE_NAME_WELCOME_PKCE]: WELCOME_SERVICE_PKCE_PROFILE,
217
+ [PROFILE_NAME_WELCOME_PKCE_ALIAS]: WELCOME_SERVICE_PKCE_PROFILE,
141
218
  [PROFILE_NAME_DIRECT]: DIRECT_PROFILE,
219
+ [PROFILE_NAME_DIRECT_PKCE]: DIRECT_PKCE_PROFILE,
220
+ [PROFILE_NAME_DIRECT_PKCE_ALIAS]: DIRECT_PKCE_PROFILE,
142
221
  [PROFILE_NAME_DIRECT_HTTP]: DIRECT_HTTP_PROFILE,
143
222
  [PROFILE_NAME_DIRECT_INPAGE]: DIRECT_INPAGE_PROFILE,
144
223
  [PROFILE_NAME_DIRECT_INPAGE_ALIAS]: DIRECT_INPAGE_PROFILE,
@@ -0,0 +1,134 @@
1
+ import { CredentialProviderFactory, } from '../credential/credential-provider-factory.js';
2
+ import { normalizeSecretSource, } from '../credential/secret-source.js';
3
+ import { safeImport } from '../../util/lazy-import.js';
4
+ import { TOKEN_PROVIDER_FACTORY_BASE_TYPE, TokenProviderFactory, } from './token-provider-factory.js';
5
+ let oauth2PkceTokenProviderModulePromise = null;
6
+ async function getOAuth2PkceTokenProviderModule() {
7
+ if (!oauth2PkceTokenProviderModulePromise) {
8
+ oauth2PkceTokenProviderModulePromise = safeImport(() => import('./oauth2-pkce-token-provider.js'), 'oauth2-pkce-token-provider');
9
+ }
10
+ return oauth2PkceTokenProviderModulePromise;
11
+ }
12
+ function ensureNonEmptyString(value, field) {
13
+ if (typeof value !== 'string' || value.trim().length === 0) {
14
+ throw new Error(`OAuth2PkceTokenProvider ${field} must be a non-empty string`);
15
+ }
16
+ return value.trim();
17
+ }
18
+ function normalizeScopes(value) {
19
+ if (Array.isArray(value)) {
20
+ const scopes = value
21
+ .map((scope) => (typeof scope === 'string' ? scope.trim() : ''))
22
+ .filter((scope) => scope.length > 0);
23
+ return scopes;
24
+ }
25
+ if (typeof value === 'string' && value.trim().length > 0) {
26
+ return value
27
+ .split(/[\s,]+/u)
28
+ .map((scope) => scope.trim())
29
+ .filter((scope) => scope.length > 0);
30
+ }
31
+ return [];
32
+ }
33
+ function normalizeConfig(config) {
34
+ if (!config) {
35
+ throw new Error('OAuth2PkceTokenProvider requires configuration');
36
+ }
37
+ const candidate = config;
38
+ const authorizeUrl = ensureNonEmptyString(candidate.authorizeUrl ?? candidate.authorize_url, 'authorizeUrl');
39
+ const tokenUrl = ensureNonEmptyString(candidate.tokenUrl ?? candidate.token_url, 'tokenUrl');
40
+ const redirectUri = ensureNonEmptyString(candidate.redirectUri ?? candidate.redirect_uri, 'redirectUri');
41
+ const clientId = ensureNonEmptyString(candidate.clientId ?? candidate.client_id, 'clientId');
42
+ const usernameSource = (candidate.username ??
43
+ candidate.username_source);
44
+ const clientSecretSource = (candidate.clientSecret ??
45
+ candidate.client_secret);
46
+ const scopes = normalizeScopes(candidate.scopes ?? candidate.scope);
47
+ const normalized = {
48
+ authorizeUrl,
49
+ tokenUrl,
50
+ redirectUri,
51
+ clientId,
52
+ scopes,
53
+ };
54
+ if (usernameSource) {
55
+ normalized.usernameConfig = normalizeSecretSource(usernameSource);
56
+ }
57
+ if (clientSecretSource) {
58
+ normalized.clientSecretConfig = normalizeSecretSource(clientSecretSource);
59
+ }
60
+ const audienceCandidate = candidate.audience ?? candidate.aud;
61
+ if (typeof audienceCandidate === 'string' && audienceCandidate.trim().length > 0) {
62
+ normalized.audience = audienceCandidate.trim();
63
+ }
64
+ const codeChallengeMethod = candidate.codeChallengeMethod ?? candidate.code_challenge_method;
65
+ if (typeof codeChallengeMethod === 'string' && codeChallengeMethod.trim().length > 0) {
66
+ normalized.codeChallengeMethod = codeChallengeMethod.trim();
67
+ }
68
+ const codeVerifierLength = candidate.codeVerifierLength ?? candidate.code_verifier_length;
69
+ if (typeof codeVerifierLength === 'number' && Number.isFinite(codeVerifierLength)) {
70
+ normalized.codeVerifierLength = codeVerifierLength;
71
+ }
72
+ const clockSkewSeconds = candidate.clockSkewSeconds ?? candidate.clock_skew_seconds;
73
+ if (typeof clockSkewSeconds === 'number' && Number.isFinite(clockSkewSeconds)) {
74
+ normalized.clockSkewSeconds = clockSkewSeconds;
75
+ }
76
+ const loginHintParam = candidate.loginHintParam ?? candidate.login_hint_param;
77
+ if (typeof loginHintParam === 'string' && loginHintParam.trim().length > 0) {
78
+ normalized.loginHintParam = loginHintParam.trim();
79
+ }
80
+ return normalized;
81
+ }
82
+ export const FACTORY_META = {
83
+ base: TOKEN_PROVIDER_FACTORY_BASE_TYPE,
84
+ key: 'OAuth2PkceTokenProvider',
85
+ };
86
+ export class OAuth2PkceTokenProviderFactory extends TokenProviderFactory {
87
+ constructor() {
88
+ super(...arguments);
89
+ this.type = 'OAuth2PkceTokenProvider';
90
+ }
91
+ async create(config) {
92
+ const normalized = normalizeConfig(config);
93
+ const [usernameProvider, clientSecretProvider] = await Promise.all([
94
+ normalized.usernameConfig
95
+ ? CredentialProviderFactory.createCredentialProvider(normalized.usernameConfig)
96
+ : Promise.resolve(undefined),
97
+ normalized.clientSecretConfig
98
+ ? CredentialProviderFactory.createCredentialProvider(normalized.clientSecretConfig)
99
+ : Promise.resolve(undefined),
100
+ ]);
101
+ const options = {
102
+ authorizeUrl: normalized.authorizeUrl,
103
+ tokenUrl: normalized.tokenUrl,
104
+ redirectUri: normalized.redirectUri,
105
+ clientId: normalized.clientId,
106
+ scopes: normalized.scopes,
107
+ };
108
+ if (usernameProvider) {
109
+ options.usernameProvider = usernameProvider;
110
+ }
111
+ if (clientSecretProvider) {
112
+ options.clientSecretProvider = clientSecretProvider;
113
+ }
114
+ if (normalized.audience) {
115
+ options.audience = normalized.audience;
116
+ }
117
+ if (normalized.codeChallengeMethod) {
118
+ options.codeChallengeMethod = normalized.codeChallengeMethod
119
+ .toUpperCase();
120
+ }
121
+ if (normalized.codeVerifierLength) {
122
+ options.codeVerifierLength = normalized.codeVerifierLength;
123
+ }
124
+ if (normalized.clockSkewSeconds) {
125
+ options.clockSkewSeconds = normalized.clockSkewSeconds;
126
+ }
127
+ if (normalized.loginHintParam) {
128
+ options.loginHintParam = normalized.loginHintParam;
129
+ }
130
+ const { OAuth2PkceTokenProvider } = await getOAuth2PkceTokenProviderModule();
131
+ return new OAuth2PkceTokenProvider(options);
132
+ }
133
+ }
134
+ export default OAuth2PkceTokenProviderFactory;