@absolutejs/auth 0.50.0 → 0.51.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.
package/dist/index.d.ts CHANGED
@@ -12,7 +12,7 @@ import { AuthConfig } from './types';
12
12
  * `UserType`); the routes are reached by path at runtime / direct fetch. */
13
13
  type MergeAuthContext<Base, Extra> = Base extends Elysia<infer Path, infer Singleton, infer Definitions, infer Metadata, infer Routes, infer Ephemeral, infer Volatile> ? Extra extends Elysia<infer ExtraPath, infer ExtraSingleton, infer ExtraDefinitions, infer ExtraMetadata, infer ExtraRoutes, infer ExtraEphemeral, infer ExtraVolatile> ? Elysia<Path & ExtraPath, Singleton & ExtraSingleton, Definitions & ExtraDefinitions, Metadata & ExtraMetadata, Routes & ExtraRoutes, Ephemeral & ExtraEphemeral, Volatile & ExtraVolatile> : never : never;
14
14
  export type AuthInstance<UserType> = MergeAuthContext<ReturnType<typeof protectRoutePlugin<UserType>>, ReturnType<typeof stepUpPlugin<UserType>>>;
15
- export declare const auth: <UserType>({ providersConfiguration, authorizeRoute, cookieSecure, callbackRoute, profileRoute, signoutRoute, statusRoute, refreshRoute, revokeRoute, cleanupIntervalMs, maxSessions, sessionDurationMs, authSessionStore, audit, credentials, mfa, passwordless, lockout, sessions, sso, scim, apikeys, oidc, organizations, roles, portal, authorization, compliance, webauthn, webhooks, htmx, tracing, resolveAuthIntent, onAuthorizeSuccess, onAuthorizeError, onProfileSuccess, onProfileError, onCallbackSuccess, onLinkIdentity, onLinkIdentityConflict, onLinkConnector, onCallbackError, onStatus, onRefreshSuccess, onRefreshError, onSignOut, onRevocationSuccess, onRevocationError, onSessionCleanup }: AuthConfig<UserType>) => Promise<Elysia<"", {
15
+ export declare const auth: <UserType>({ providersConfiguration, authorizeRoute, cookieSecure, callbackRoute, profileRoute, signoutRoute, statusRoute, refreshRoute, revokeRoute, cleanupIntervalMs, maxSessions, sessionDurationMs, authSessionStore, audit, credentials, customProviders, mfa, passwordless, lockout, sessions, sso, scim, apikeys, oidc, organizations, roles, portal, authorization, compliance, webauthn, webhooks, htmx, tracing, resolveAuthIntent, onAuthorizeSuccess, onAuthorizeError, onProfileSuccess, onProfileError, onCallbackSuccess, onLinkIdentity, onLinkIdentityConflict, onLinkConnector, onCallbackError, onStatus, onRefreshSuccess, onRefreshError, onSignOut, onRevocationSuccess, onRevocationError, onSessionCleanup }: AuthConfig<UserType>) => Promise<Elysia<"", {
16
16
  decorator: {};
17
17
  store: {
18
18
  session: import("./types").SessionRecord<UserType>;
@@ -127,8 +127,8 @@ export { resolveAuthHtmxRenderers } from './htmx/renderers';
127
127
  export type { AuthHtmxConfig, AuthHtmxConnectorTarget, AuthHtmxProviderData, AuthHtmxProviderInfo, AuthHtmxRenderOverrides, AuthHtmxRenderersConfig, AuthHtmxUser, AuthIdentityPayload, LinkedProviderPayload } from './htmx/types';
128
128
  export * from './utils';
129
129
  export { buildClientProviders, resolveClientProviderEntry, resolveProviderClientConfiguration } from './providers/clients';
130
- export type { OAuth2TokenResponse, OAuth2Client, ProviderOption, PKCEProvider, OIDCProvider, RefreshableProvider, RevocableProvider, ScopeRequiredProvider, ProvidersMap, ProviderConfiguration, CredentialsFor } from 'citra';
131
- export { providers, providerOptions, refreshableProviderOptions, revocableProviderOptions, oidcProviderOptions, pkceProviderOptions, scopeRequiredProviderOptions, decodeJWT, extractPropFromIdentity, isValidProviderOption, isRefreshableOAuth2Client, isRefreshableProviderOption, isOIDCProviderOption, isPKCEProviderOption, isRevocableProviderOption, isRevocableOAuth2Client } from 'citra';
130
+ export type { OAuth2TokenResponse, OAuth2Client, OAuth2ClientForConfig, CustomProviderCredentials, ProviderConfig, ProviderOption, PKCEProvider, OIDCProvider, RefreshableProvider, RevocableProvider, ScopeRequiredProvider, ProvidersMap, ProviderConfiguration, CredentialsFor } from 'citra';
131
+ export { providers, providerOptions, createCustomOAuth2Client, defineProvider, refreshableProviderOptions, revocableProviderOptions, oidcProviderOptions, pkceProviderOptions, scopeRequiredProviderOptions, decodeJWT, extractPropFromIdentity, isValidProviderOption, isRefreshableOAuth2Client, isRefreshableProviderOption, isOIDCProviderOption, isPKCEProviderOption, isRevocableProviderOption, isRevocableOAuth2Client } from 'citra';
132
132
  export * from './crypto';
133
133
  export * from './tenancy';
134
134
  export * from './credentials/config';
package/dist/index.js CHANGED
@@ -262,6 +262,7 @@ var anilistProfileQuery = `query {
262
262
  }
263
263
  }`;
264
264
  var defineProviders = (providers) => providers;
265
+ var defineProvider = (config) => config;
265
266
  var providers = defineProviders({
266
267
  "42": {
267
268
  authorizationUrl: "https://api.intra.42.fr/oauth/authorize",
@@ -1347,6 +1348,37 @@ var providers = defineProviders({
1347
1348
  url: (config) => `https://${config.domain}/oauth2/default/v1/token`
1348
1349
  }
1349
1350
  },
1351
+ onspark: {
1352
+ authorizationUrl: "https://app.onspark.com/oauth2/authorize",
1353
+ email: ["email"],
1354
+ familyName: ["family_name"],
1355
+ fullName: ["name"],
1356
+ givenName: ["given_name"],
1357
+ isOIDC: true,
1358
+ isRefreshable: true,
1359
+ picture: ["picture"],
1360
+ PKCEMethod: "S256",
1361
+ profileRequest: {
1362
+ authIn: "header",
1363
+ encoding: "application/json",
1364
+ method: "GET",
1365
+ url: "https://app.onspark.com/oauth2/userinfo"
1366
+ },
1367
+ revocationRequest: {
1368
+ authIn: "body",
1369
+ encoding: "application/x-www-form-urlencoded",
1370
+ tokenParamName: "token",
1371
+ url: "https://app.onspark.com/oauth2/revoke"
1372
+ },
1373
+ scopeRequired: true,
1374
+ subject: ["sub"],
1375
+ subjectType: "string",
1376
+ tokenRequest: {
1377
+ authIn: "body",
1378
+ encoding: "application/x-www-form-urlencoded",
1379
+ url: "https://app.onspark.com/oauth2/token"
1380
+ }
1381
+ },
1350
1382
  osu: {
1351
1383
  authorizationUrl: "https://osu.ppy.sh/oauth/authorize",
1352
1384
  isOIDC: false,
@@ -1898,6 +1930,7 @@ var providers = defineProviders({
1898
1930
  method: "POST",
1899
1931
  url: "https://wbsapi.withings.net/v2/oauth2"
1900
1932
  },
1933
+ scopeDelimiter: ",",
1901
1934
  scopeRequired: true,
1902
1935
  subject: ["userid"],
1903
1936
  subjectType: "string",
@@ -2529,8 +2562,7 @@ var refreshableProviderOptions = Object.keys(providers).filter(isRefreshableProv
2529
2562
  var revocableProviderOptions = Object.keys(providers).filter(isRevocableProviderOption);
2530
2563
  var scopeRequiredProviderOptions = Object.keys(providers).filter(isScopeRequiredProviderOption);
2531
2564
  var readPath = (value, path) => path.reduce((cursor, key) => cursor && typeof cursor === "object" ? Reflect.get(cursor, key) : undefined, value);
2532
- var createOAuth2Client = async (providerName, config) => {
2533
- const meta = providers[providerName];
2565
+ var buildOAuth2Client = async (meta, config) => {
2534
2566
  const isConfigPropertyFunction = (cfgProp) => typeof cfgProp === "function";
2535
2567
  const resolveConfigProp = async (cfgProp) => {
2536
2568
  const result = isConfigPropertyFunction(cfgProp) ? cfgProp(config) : cfgProp;
@@ -2549,8 +2581,7 @@ var createOAuth2Client = async (providerName, config) => {
2549
2581
  if (state)
2550
2582
  url.searchParams.set("state", state);
2551
2583
  if (scope.length !== 0) {
2552
- const delimeter = providerName === "withings" ? "," : " ";
2553
- url.searchParams.set(meta.scopeParamName ?? "scope", scope.join(delimeter));
2584
+ url.searchParams.set(meta.scopeParamName ?? "scope", scope.join(meta.scopeDelimiter ?? " "));
2554
2585
  }
2555
2586
  if (meta.PKCEMethod !== undefined) {
2556
2587
  if (!codeVerifier) {
@@ -2732,6 +2763,8 @@ var createOAuth2Client = async (providerName, config) => {
2732
2763
  }
2733
2764
  };
2734
2765
  };
2766
+ var createCustomOAuth2Client = (providerConfig, credentials) => buildOAuth2Client(providerConfig, credentials);
2767
+ var createOAuth2Client = (providerName, config) => buildOAuth2Client(providers[providerName], config);
2735
2768
 
2736
2769
  // src/index.ts
2737
2770
  import { Elysia as Elysia40 } from "elysia";
@@ -3201,7 +3234,7 @@ var authIntentOption = t2.Optional(t2.Union([
3201
3234
  t2.Literal("link_identity"),
3202
3235
  t2.Literal("link_connector")
3203
3236
  ]));
3204
- var authProviderOption = t2.Enum(Object.fromEntries(Object.keys(providers).filter(isValidProviderOption).map((key) => [key, key])));
3237
+ var authProviderOption = t2.String({ minLength: 1 });
3205
3238
  var userSessionIdTypebox = t2.Optional(t2.TemplateLiteral("${string}-${string}-${string}-${string}-${string}"));
3206
3239
 
3207
3240
  // src/authorization/protectPermission.ts
@@ -3273,6 +3306,7 @@ var getStatus = async (session, user_session_id) => {
3273
3306
  };
3274
3307
  var instantiateUserSession = async ({
3275
3308
  authProvider,
3309
+ providerConfiguration,
3276
3310
  cookieSecure,
3277
3311
  session,
3278
3312
  user_session_id,
@@ -3287,6 +3321,7 @@ var instantiateUserSession = async ({
3287
3321
  }) => {
3288
3322
  const authorization = resolvedAuthorization ?? await resolveOAuthAuthorization({
3289
3323
  authProvider,
3324
+ providerConfiguration,
3290
3325
  providerInstance,
3291
3326
  tokenResponse
3292
3327
  });
@@ -3331,23 +3366,28 @@ var instantiateUserSession = async ({
3331
3366
  var resolveCookieSecure = (override) => override ?? false;
3332
3367
  var resolveOAuthAuthorization = async ({
3333
3368
  authProvider,
3369
+ providerConfiguration,
3334
3370
  providerInstance,
3335
3371
  tokenResponse,
3336
3372
  now = Date.now()
3337
3373
  }) => {
3374
+ const meta = providerConfiguration ?? (isValidProviderOption(authProvider) ? providers[authProvider] : undefined);
3375
+ if (!meta) {
3376
+ throw new Error(`No provider configuration for "${authProvider}" \u2014 pass providerConfiguration (custom provider) or resolvedAuthorization`);
3377
+ }
3338
3378
  let userIdentity;
3339
3379
  let accessToken = tokenResponse.access_token;
3340
3380
  let refreshToken = tokenResponse.refresh_token;
3341
3381
  if (tokenResponse.id_token) {
3342
3382
  userIdentity = normalizeProviderIdentity({
3343
3383
  identity: decodeJWT(tokenResponse.id_token),
3344
- providerConfiguration: providers[authProvider],
3384
+ providerConfiguration: meta,
3345
3385
  source: "idToken"
3346
3386
  });
3347
- } else if (providers[authProvider].subjectBySource?.tokenResponse) {
3387
+ } else if (meta.subjectBySource?.tokenResponse) {
3348
3388
  userIdentity = normalizeProviderIdentity({
3349
3389
  identity: tokenResponse,
3350
- providerConfiguration: providers[authProvider],
3390
+ providerConfiguration: meta,
3351
3391
  source: "tokenResponse"
3352
3392
  });
3353
3393
  } else if (authProvider === "withings") {
@@ -3357,7 +3397,7 @@ var resolveOAuthAuthorization = async ({
3357
3397
  } else {
3358
3398
  userIdentity = normalizeProviderIdentity({
3359
3399
  identity: await providerInstance.fetchUserProfile(tokenResponse.access_token),
3360
- providerConfiguration: providers[authProvider],
3400
+ providerConfiguration: meta,
3361
3401
  source: "profile"
3362
3402
  });
3363
3403
  }
@@ -8267,7 +8307,52 @@ var roleRoutes = ({
8267
8307
  // src/providers/clients.ts
8268
8308
  var isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
8269
8309
  var isProviderClientConfig = (value) => isRecord(value) && ("credentials" in value);
8270
- var buildClientProviders = async (providersConfiguration, createOAuth2ClientFn) => {
8310
+ var isCustomClientConfig = (value) => isRecord(value) && ("credentials" in value) && ("providerConfig" in value);
8311
+ var normalizeCustomClients = (providerName, providerConfig) => {
8312
+ if (isCustomClientConfig(providerConfig))
8313
+ return { "": providerConfig };
8314
+ if (!isRecord(providerConfig) || Object.keys(providerConfig).length === 0) {
8315
+ throw new Error(`Invalid custom provider configuration for ${providerName}`);
8316
+ }
8317
+ Object.entries(providerConfig).forEach(([clientName, clientConfig]) => {
8318
+ if (!isCustomClientConfig(clientConfig)) {
8319
+ throw new Error(`Invalid custom client configuration for ${providerName}.${clientName}`);
8320
+ }
8321
+ });
8322
+ return providerConfig;
8323
+ };
8324
+ var buildCustomProviderGroups = async (customProviders) => {
8325
+ const groups = await Promise.all(Object.entries(customProviders).map(async ([providerName, config]) => {
8326
+ if (isValidProviderOption(providerName)) {
8327
+ throw new Error(`Custom provider "${providerName}" collides with a built-in provider \u2014 configure it under providersConfiguration instead`);
8328
+ }
8329
+ const clients = normalizeCustomClients(providerName, config);
8330
+ const entries = await Promise.all(Object.entries(clients).map(async ([clientName, clientConfig]) => {
8331
+ const providerInstance = await createCustomOAuth2Client(clientConfig.providerConfig, clientConfig.credentials);
8332
+ return [
8333
+ clientName,
8334
+ {
8335
+ clientName: clientName.length > 0 ? clientName : undefined,
8336
+ providerConfiguration: clientConfig.providerConfig,
8337
+ providerInstance,
8338
+ requiresPKCE: clientConfig.providerConfig.PKCEMethod !== undefined,
8339
+ scope: clientConfig.scope,
8340
+ searchParams: clientConfig.searchParams
8341
+ }
8342
+ ];
8343
+ }));
8344
+ return [
8345
+ providerName,
8346
+ {
8347
+ entries: Object.fromEntries(entries),
8348
+ isSingleClient: entries.length === 1 && entries[0]?.[0] === ""
8349
+ }
8350
+ ];
8351
+ }));
8352
+ return Object.fromEntries(groups);
8353
+ };
8354
+ var buildClientProviders = async (providersConfiguration, createOAuth2ClientFn, customProviders) => {
8355
+ const customGroups = customProviders ? await buildCustomProviderGroups(customProviders) : {};
8271
8356
  const normalized = normalizeProvidersConfiguration(providersConfiguration);
8272
8357
  const groups = await Promise.all(Object.entries(normalized).map(async ([providerName, clients]) => {
8273
8358
  if (!isValidProviderOption(providerName)) {
@@ -8279,7 +8364,9 @@ var buildClientProviders = async (providersConfiguration, createOAuth2ClientFn)
8279
8364
  clientName,
8280
8365
  {
8281
8366
  clientName: clientName.length > 0 ? clientName : undefined,
8367
+ providerConfiguration: providers[providerName],
8282
8368
  providerInstance,
8369
+ requiresPKCE: providers[providerName].PKCEMethod !== undefined,
8283
8370
  scope: providerConfig.scope,
8284
8371
  searchParams: providerConfig.searchParams
8285
8372
  }
@@ -8293,7 +8380,7 @@ var buildClientProviders = async (providersConfiguration, createOAuth2ClientFn)
8293
8380
  }
8294
8381
  ];
8295
8382
  }));
8296
- return Object.fromEntries(groups);
8383
+ return { ...customGroups, ...Object.fromEntries(groups) };
8297
8384
  };
8298
8385
  var normalizeClientConfig = (providerName, clientName, clientConfig) => {
8299
8386
  if (!isProviderClientConfig(clientConfig)) {
@@ -8429,7 +8516,13 @@ var authorize = ({
8429
8516
  if ("error" in resolvedProvider) {
8430
8517
  return status("Unauthorized", resolvedProvider.error);
8431
8518
  }
8432
- const { clientName, providerInstance, scope, searchParams } = resolvedProvider.entry;
8519
+ const {
8520
+ clientName,
8521
+ providerInstance,
8522
+ requiresPKCE,
8523
+ scope,
8524
+ searchParams
8525
+ } = resolvedProvider.entry;
8433
8526
  const referer = parseReferer(headers["referer"]);
8434
8527
  const authIntent = isAuthIntent(intent) ? intent : undefined;
8435
8528
  origin_url.set({
@@ -8477,7 +8570,7 @@ var authorize = ({
8477
8570
  secure,
8478
8571
  value: currentState
8479
8572
  });
8480
- const codeVerifier = isPKCEProviderOption(provider) ? generateCodeVerifier() : undefined;
8573
+ const codeVerifier = requiresPKCE ? generateCodeVerifier() : undefined;
8481
8574
  if (codeVerifier) {
8482
8575
  code_verifier.set({
8483
8576
  httpOnly: true,
@@ -8589,9 +8682,13 @@ var callback = ({
8589
8682
  if ("error" in resolvedProvider) {
8590
8683
  return status("Unauthorized", resolvedProvider.error);
8591
8684
  }
8592
- const { clientName, providerInstance } = resolvedProvider.entry;
8685
+ const {
8686
+ clientName,
8687
+ providerConfiguration,
8688
+ providerInstance,
8689
+ requiresPKCE
8690
+ } = resolvedProvider.entry;
8593
8691
  stored_state.remove();
8594
- const requiresPKCE = isPKCEProviderOption(authProvider);
8595
8692
  const verifier = requiresPKCE ? code_verifier.value : undefined;
8596
8693
  if (requiresPKCE && verifier === undefined) {
8597
8694
  return status("Bad Request", "Code verifier not found and is required");
@@ -8639,6 +8736,7 @@ var callback = ({
8639
8736
  cookie,
8640
8737
  currentUser,
8641
8738
  originUrl,
8739
+ providerConfiguration,
8642
8740
  providerInstance,
8643
8741
  redirect,
8644
8742
  session: callbackSession,
@@ -27333,6 +27431,7 @@ var auth = async ({
27333
27431
  authSessionStore,
27334
27432
  audit,
27335
27433
  credentials,
27434
+ customProviders,
27336
27435
  mfa,
27337
27436
  passwordless,
27338
27437
  lockout,
@@ -27370,7 +27469,7 @@ var auth = async ({
27370
27469
  }) => {
27371
27470
  if (tracing !== undefined)
27372
27471
  await initTracing(tracing);
27373
- const clientProviders = await buildClientProviders(providersConfiguration, createOAuth2Client);
27472
+ const clientProviders = await buildClientProviders(providersConfiguration, createOAuth2Client, customProviders);
27374
27473
  const resolvedCookieSecure = resolveCookieSecure(cookieSecure);
27375
27474
  const webhookDispatch = webhooks ? createWebhookDispatcher(webhooks) : undefined;
27376
27475
  const auditEmit = audit || webhookDispatch ? createAuditEmitter({
@@ -27700,6 +27799,7 @@ export {
27700
27799
  deleteRegisteredClient,
27701
27800
  defineScimAttributeMap,
27702
27801
  defineProvidersConfiguration,
27802
+ defineProvider,
27703
27803
  defineAuthSettings,
27704
27804
  defineAuthHtmxConfig,
27705
27805
  defineAuthConfig,
@@ -27845,6 +27945,7 @@ export {
27845
27945
  createInMemoryAccessTokenStore,
27846
27946
  createFgaEngine,
27847
27947
  createFederatedTokenStore,
27948
+ createCustomOAuth2Client,
27848
27949
  createCredentialOffer,
27849
27950
  createAuthHtmxRoutes,
27850
27951
  createAuditRedactor,
@@ -27927,5 +28028,5 @@ export {
27927
28028
  AuthIdentityConflictError
27928
28029
  };
27929
28030
 
27930
- //# debugId=47718768D4F1D77064756E2164756E21
28031
+ //# debugId=CF57DC7D601D3EC464756E2164756E21
27931
28032
  //# sourceMappingURL=index.js.map