@authup/server-core 1.0.0-beta.60 → 1.0.0-beta.61

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 (60) hide show
  1. package/dist/adapters/http/controllers/entities/identity-provider/module.d.ts +10 -4
  2. package/dist/adapters/http/controllers/entities/identity-provider/module.d.ts.map +1 -1
  3. package/dist/adapters/http/controllers/entities/identity-provider/module.mjs +125 -48
  4. package/dist/adapters/http/controllers/entities/identity-provider/module.mjs.map +1 -1
  5. package/dist/adapters/http/controllers/entities/identity-provider/types.d.ts +2 -2
  6. package/dist/adapters/http/controllers/entities/identity-provider/types.d.ts.map +1 -1
  7. package/dist/app/index.mjs +3 -1
  8. package/dist/app/modules/http/modules/controller.mjs +2 -1
  9. package/dist/app/modules/http/modules/controller.mjs.map +1 -1
  10. package/dist/app/modules/identity/constants.d.ts +2 -1
  11. package/dist/app/modules/identity/constants.d.ts.map +1 -1
  12. package/dist/app/modules/identity/constants.mjs +1 -0
  13. package/dist/app/modules/identity/constants.mjs.map +1 -1
  14. package/dist/app/modules/identity/index.mjs +3 -1
  15. package/dist/app/modules/identity/module.d.ts.map +1 -1
  16. package/dist/app/modules/identity/module.mjs +7 -0
  17. package/dist/app/modules/identity/module.mjs.map +1 -1
  18. package/dist/app/modules/identity/repositories/constants.d.ts +4 -0
  19. package/dist/app/modules/identity/repositories/constants.d.ts.map +1 -0
  20. package/dist/app/modules/identity/repositories/constants.mjs +12 -0
  21. package/dist/app/modules/identity/repositories/constants.mjs.map +1 -0
  22. package/dist/app/modules/identity/repositories/index.d.ts +1 -0
  23. package/dist/app/modules/identity/repositories/index.d.ts.map +1 -1
  24. package/dist/app/modules/identity/repositories/index.mjs +3 -1
  25. package/dist/app/modules/identity/repositories/provider/index.d.ts +1 -0
  26. package/dist/app/modules/identity/repositories/provider/index.d.ts.map +1 -1
  27. package/dist/app/modules/identity/repositories/provider/index.mjs +2 -1
  28. package/dist/app/modules/identity/repositories/provider/link.d.ts +9 -0
  29. package/dist/app/modules/identity/repositories/provider/link.d.ts.map +1 -0
  30. package/dist/app/modules/identity/repositories/provider/link.mjs +34 -0
  31. package/dist/app/modules/identity/repositories/provider/link.mjs.map +1 -0
  32. package/dist/app/modules/index.mjs +3 -1
  33. package/dist/core/identity/index.mjs +2 -1
  34. package/dist/core/identity/provider/account/constants.d.ts +10 -0
  35. package/dist/core/identity/provider/account/constants.d.ts.map +1 -0
  36. package/dist/core/identity/provider/account/constants.mjs +16 -0
  37. package/dist/core/identity/provider/account/constants.mjs.map +1 -0
  38. package/dist/core/identity/provider/account/index.d.ts +1 -0
  39. package/dist/core/identity/provider/account/index.d.ts.map +1 -1
  40. package/dist/core/identity/provider/account/index.mjs +2 -1
  41. package/dist/core/identity/provider/account/types.d.ts +35 -0
  42. package/dist/core/identity/provider/account/types.d.ts.map +1 -1
  43. package/dist/core/identity/provider/authentication/protocols/oauth2/module.d.ts +18 -0
  44. package/dist/core/identity/provider/authentication/protocols/oauth2/module.d.ts.map +1 -1
  45. package/dist/core/identity/provider/authentication/protocols/oauth2/module.mjs +55 -2
  46. package/dist/core/identity/provider/authentication/protocols/oauth2/module.mjs.map +1 -1
  47. package/dist/core/identity/provider/authentication/protocols/oauth2/types.d.ts +2 -0
  48. package/dist/core/identity/provider/authentication/protocols/oauth2/types.d.ts.map +1 -1
  49. package/dist/core/identity/provider/authentication/protocols/open-id/module.d.ts +0 -3
  50. package/dist/core/identity/provider/authentication/protocols/open-id/module.d.ts.map +1 -1
  51. package/dist/core/identity/provider/authentication/protocols/open-id/module.mjs +0 -17
  52. package/dist/core/identity/provider/authentication/protocols/open-id/module.mjs.map +1 -1
  53. package/dist/core/identity/provider/index.mjs +2 -1
  54. package/dist/core/index.mjs +2 -1
  55. package/dist/core/oauth2/authorization/code-request/verifier/module.d.ts.map +1 -1
  56. package/dist/core/oauth2/authorization/code-request/verifier/module.mjs +2 -1
  57. package/dist/core/oauth2/authorization/code-request/verifier/module.mjs.map +1 -1
  58. package/dist/index.mjs +3 -1
  59. package/dist/swagger.json +116 -16
  60. package/package.json +12 -12
@@ -0,0 +1,34 @@
1
+ import "node:path";
2
+ import "node:url";
3
+ import.meta.url;
4
+ import { IDENTITY_PROVIDER_ACCOUNT_LINK_TTL } from "../../../../../core/identity/provider/account/constants.mjs";
5
+ import "../../../../../core/index.mjs";
6
+ import { CacheIdentityPrefix } from "../constants.mjs";
7
+ import { createNanoID } from "@authup/kit";
8
+ import { buildCacheKey } from "@authup/server-kit";
9
+ //#region src/app/modules/identity/repositories/provider/link.ts
10
+ var IdentityProviderAccountLinkStore = class {
11
+ cache;
12
+ constructor(cache) {
13
+ this.cache = cache;
14
+ }
15
+ async save(data) {
16
+ const handle = createNanoID();
17
+ await this.cache.set(buildCacheKey({
18
+ prefix: CacheIdentityPrefix.PROVIDER_ACCOUNT_LINK,
19
+ key: handle
20
+ }), data, { ttl: IDENTITY_PROVIDER_ACCOUNT_LINK_TTL });
21
+ return handle;
22
+ }
23
+ async consume(handle) {
24
+ const key = buildCacheKey({
25
+ prefix: CacheIdentityPrefix.PROVIDER_ACCOUNT_LINK,
26
+ key: handle
27
+ });
28
+ return this.cache.pop(key);
29
+ }
30
+ };
31
+ //#endregion
32
+ export { IdentityProviderAccountLinkStore };
33
+
34
+ //# sourceMappingURL=link.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"link.mjs","names":["createNanoID","buildCacheKey","IDENTITY_PROVIDER_ACCOUNT_LINK_TTL","CacheIdentityPrefix","IdentityProviderAccountLinkStore","cache","save","data","handle","set","prefix","PROVIDER_ACCOUNT_LINK","key","ttl","consume","pop"],"sources":["../../../../../../src/app/modules/identity/repositories/provider/link.ts"],"sourcesContent":["/*\n * Copyright (c) 2026.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport { createNanoID } from '@authup/kit';\nimport type { ICache } from '@authup/server-kit';\nimport { buildCacheKey } from '@authup/server-kit';\nimport type {\n IIdentityProviderAccountLinkStore,\n IdentityProviderAccountLink,\n} from '../../../../../core/index.ts';\nimport { IDENTITY_PROVIDER_ACCOUNT_LINK_TTL } from '../../../../../core/index.ts';\nimport { CacheIdentityPrefix } from '../constants.ts';\n\nexport class IdentityProviderAccountLinkStore implements IIdentityProviderAccountLinkStore {\n protected cache : ICache;\n\n constructor(cache: ICache) {\n this.cache = cache;\n }\n\n async save(data: IdentityProviderAccountLink): Promise<string> {\n const handle = createNanoID();\n\n await this.cache.set(\n buildCacheKey({\n prefix: CacheIdentityPrefix.PROVIDER_ACCOUNT_LINK,\n key: handle,\n }),\n data,\n { ttl: IDENTITY_PROVIDER_ACCOUNT_LINK_TTL },\n );\n\n return handle;\n }\n\n async consume(handle: string): Promise<IdentityProviderAccountLink | null> {\n const key = buildCacheKey({\n prefix: CacheIdentityPrefix.PROVIDER_ACCOUNT_LINK,\n key: handle,\n });\n\n // `pop` is the atomic read-and-drop (redis GETDEL, one tick on the\n // memory adapter). A get followed by a drop is two round-trips, and\n // two simultaneous redemptions of one handle would both read the\n // payload before either drop landed.\n return this.cache.pop<IdentityProviderAccountLink>(key);\n }\n}\n"],"mappings":";;;;;;;;;AAiBA,IAAaI,mCAAb,MAAaA;CACCC;CAEV,YAAYA,OAAe;EACvB,KAAKA,QAAQA;CACjB;CAEA,MAAMC,KAAKC,MAAoD;EAC3D,MAAMC,SAASR,aAAAA;EAEf,MAAM,KAAKK,MAAMI,IACbR,cAAc;GACVS,QAAQP,oBAAoBQ;GAC5BC,KAAKJ;EACT,CAAA,GACAD,MACA,EAAEM,KAAKX,mCAAmC,CAAA;EAG9C,OAAOM;CACX;CAEA,MAAMM,QAAQN,QAA6D;EACvE,MAAMI,MAAMX,cAAc;GACtBS,QAAQP,oBAAoBQ;GAC5BC,KAAKJ;EACT,CAAA;EAMA,OAAO,KAAKH,MAAMU,IAAiCH,GAAAA;CACvD;AACJ"}
@@ -58,6 +58,8 @@ import { IdentityInjectionKey } from "./identity/constants.mjs";
58
58
  import { IdentityProviderAttributeMappingRepository } from "./identity/repositories/provider/mapper/attribute.mjs";
59
59
  import { IdentityProviderPermissionMappingRepository } from "./identity/repositories/provider/mapper/permission.mjs";
60
60
  import { IdentityProviderRoleMappingRepository } from "./identity/repositories/provider/mapper/role.mjs";
61
+ import { CacheIdentityPrefix } from "./identity/repositories/constants.mjs";
62
+ import { IdentityProviderAccountLinkStore } from "./identity/repositories/provider/link.mjs";
61
63
  import { ClientIdentityRepository } from "./identity/repositories/client.mjs";
62
64
  import { UserIdentityRepository } from "./identity/repositories/user.mjs";
63
65
  import { LDAPInjectionKey } from "./ldap/constants.mjs";
@@ -81,4 +83,4 @@ import { ProvisionerModule } from "./provisioning/module.mjs";
81
83
  import "./provisioning/index.mjs";
82
84
  import { RuntimeModule } from "./runtime/module.mjs";
83
85
  import "./runtime/index.mjs";
84
- export { AuthenticationInjectionKey, AuthenticationModule, CacheInjectionKey, CacheModule, ClientIdentityRepository, ClientPermissionRepositoryAdapter, ClientRepositoryAdapter, ClientRoleRepositoryAdapter, ClientScopeRepositoryAdapter, ComponentsModule, CompositeProvisioningSource, ConfigEnvironmentVariableName, ConfigInjectionKey, ConfigModule, DatabaseInjectionKey, DatabaseModule, DefaultProvisioningSource, EventRepositoryAdapter, FileProvisioningSource, HTTPInjectionKey, HTTPModule, IdentityInjectionKey, IdentityModule, IdentityProviderAccountRepositoryAdapter, IdentityProviderAttributeMappingRepository, IdentityProviderPermissionMappingRepository, IdentityProviderRepositoryAdapter, IdentityProviderRoleMappingRepository, IdentityProviderRoleMappingRepositoryAdapter, KeyRepositoryAdapter, LDAPInjectionKey, LazyWildcardRealmProvisioner, LdapModule, LoggerInjectionKey, LoggerModule, MailInjectionKey, MailModule, MailTemplateRendererInjectionKey, MetricsInjectionKey, ModuleName, OAuth2InjectionToken, OAuth2Module, PermissionDatabaseProvider, PermissionPolicyRepositoryAdapter, PermissionRepositoryAdapter, PolicyRepositoryAdapter, PromAuthFlowMetrics, ProvisionerModule, ProvisioningInjectionKey, RealmRepositoryAdapter, RoleAttributeRepositoryAdapter, RolePermissionRepositoryAdapter, RoleRepositoryAdapter, RuntimeModule, ScopeRepositoryAdapter, SessionRepository, TrustAnchorRepositoryAdapter, UserAttributeRepositoryAdapter, UserAuthenticatorRepositoryAdapter, UserIdentityRepository, UserPermissionRepositoryAdapter, UserRepositoryAdapter, UserRoleRepositoryAdapter, expandToOrigins, getAppOrigins, readConfig, readConfigRaw, readConfigRawFromEnv, readConfigRawFromFS };
86
+ export { AuthenticationInjectionKey, AuthenticationModule, CacheIdentityPrefix, CacheInjectionKey, CacheModule, ClientIdentityRepository, ClientPermissionRepositoryAdapter, ClientRepositoryAdapter, ClientRoleRepositoryAdapter, ClientScopeRepositoryAdapter, ComponentsModule, CompositeProvisioningSource, ConfigEnvironmentVariableName, ConfigInjectionKey, ConfigModule, DatabaseInjectionKey, DatabaseModule, DefaultProvisioningSource, EventRepositoryAdapter, FileProvisioningSource, HTTPInjectionKey, HTTPModule, IdentityInjectionKey, IdentityModule, IdentityProviderAccountLinkStore, IdentityProviderAccountRepositoryAdapter, IdentityProviderAttributeMappingRepository, IdentityProviderPermissionMappingRepository, IdentityProviderRepositoryAdapter, IdentityProviderRoleMappingRepository, IdentityProviderRoleMappingRepositoryAdapter, KeyRepositoryAdapter, LDAPInjectionKey, LazyWildcardRealmProvisioner, LdapModule, LoggerInjectionKey, LoggerModule, MailInjectionKey, MailModule, MailTemplateRendererInjectionKey, MetricsInjectionKey, ModuleName, OAuth2InjectionToken, OAuth2Module, PermissionDatabaseProvider, PermissionPolicyRepositoryAdapter, PermissionRepositoryAdapter, PolicyRepositoryAdapter, PromAuthFlowMetrics, ProvisionerModule, ProvisioningInjectionKey, RealmRepositoryAdapter, RoleAttributeRepositoryAdapter, RolePermissionRepositoryAdapter, RoleRepositoryAdapter, RuntimeModule, ScopeRepositoryAdapter, SessionRepository, TrustAnchorRepositoryAdapter, UserAttributeRepositoryAdapter, UserAuthenticatorRepositoryAdapter, UserIdentityRepository, UserPermissionRepositoryAdapter, UserRepositoryAdapter, UserRoleRepositoryAdapter, expandToOrigins, getAppOrigins, readConfig, readConfigRaw, readConfigRawFromEnv, readConfigRawFromFS };
@@ -11,6 +11,7 @@ import { IdentityPermissionProvider } from "./permission/module.mjs";
11
11
  import "./permission/index.mjs";
12
12
  import { PolicyCheckerService } from "./policy/checker/service.mjs";
13
13
  import "./policy/index.mjs";
14
+ import { IDENTITY_PROVIDER_ACCOUNT_LINK_TTL } from "./provider/account/constants.mjs";
14
15
  import { IDENTITY_PROVIDER_ACCOUNT_ALREADY_LINKED_ERROR_INSTANCE, IdentityProviderAccountAlreadyLinkedError, isIdentityProviderAccountAlreadyLinkedError } from "./provider/account/error.mjs";
15
16
  import { IdentityProviderMapperOperation } from "./provider/mapper/constants.mjs";
16
17
  import { IdentityProviderAccountBaseMapper } from "./provider/mapper/base.mjs";
@@ -35,4 +36,4 @@ import "./registration/index.mjs";
35
36
  import { IdentityResolver } from "./resolver/module.mjs";
36
37
  import "./resolver/index.mjs";
37
38
  import { IdentityRoleProvider } from "./role/module.mjs";
38
- export { IDENTITY_PROVIDER_ACCOUNT_ALREADY_LINKED_ERROR_INSTANCE, IDENTITY_PROVIDER_LDAP_COLLECTION_AUTHENTICATOR_TOKEN, IdentityPermissionProvider, IdentityProviderAccountAlreadyLinkedError, IdentityProviderAccountBaseMapper, IdentityProviderAccountManager, IdentityProviderAttributeMapper, IdentityProviderFacebookAuthenticator, IdentityProviderGithubAuthenticator, IdentityProviderGoogleAuthenticator, IdentityProviderInstagramAuthenticator, IdentityProviderLdapAuthenticator, IdentityProviderLdapCollectionAuthenticator, IdentityProviderMapperOperation, IdentityProviderOAuth2Authenticator, IdentityProviderOpenIDAuthenticator, IdentityProviderPaypalAuthenticator, IdentityProviderPermissionMapper, IdentityProviderRoleMapper, IdentityResolver, IdentityRoleProvider, PASSWORD_RESET_EXPIRES_IN_MINUTES, PasswordRecoveryService, PermissionCheckerService, PolicyCheckerService, RegistrationService, applyJunctionCreateGrant, buildJunctionUpdateData, createIdentityProviderOAuth2Authenticator, isIdentityProviderAccountAlreadyLinkedError, toIdentityPolicyData };
39
+ export { IDENTITY_PROVIDER_ACCOUNT_ALREADY_LINKED_ERROR_INSTANCE, IDENTITY_PROVIDER_ACCOUNT_LINK_TTL, IDENTITY_PROVIDER_LDAP_COLLECTION_AUTHENTICATOR_TOKEN, IdentityPermissionProvider, IdentityProviderAccountAlreadyLinkedError, IdentityProviderAccountBaseMapper, IdentityProviderAccountManager, IdentityProviderAttributeMapper, IdentityProviderFacebookAuthenticator, IdentityProviderGithubAuthenticator, IdentityProviderGoogleAuthenticator, IdentityProviderInstagramAuthenticator, IdentityProviderLdapAuthenticator, IdentityProviderLdapCollectionAuthenticator, IdentityProviderMapperOperation, IdentityProviderOAuth2Authenticator, IdentityProviderOpenIDAuthenticator, IdentityProviderPaypalAuthenticator, IdentityProviderPermissionMapper, IdentityProviderRoleMapper, IdentityResolver, IdentityRoleProvider, PASSWORD_RESET_EXPIRES_IN_MINUTES, PasswordRecoveryService, PermissionCheckerService, PolicyCheckerService, RegistrationService, applyJunctionCreateGrant, buildJunctionUpdateData, createIdentityProviderOAuth2Authenticator, isIdentityProviderAccountAlreadyLinkedError, toIdentityPolicyData };
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Lifetime of a pending account link (issue #3439).
3
+ *
4
+ * The handle is redeemed by the very next page load, so it needs to cover a
5
+ * redirect and a bootstrap, not a user's attention span. The authorization
6
+ * state's 30 minutes would leave a redeemable credential-binding handle
7
+ * lying in browser history far longer than the flow that produced it.
8
+ */
9
+ export declare const IDENTITY_PROVIDER_ACCOUNT_LINK_TTL: number;
10
+ //# sourceMappingURL=constants.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../../../src/core/identity/provider/account/constants.ts"],"names":[],"mappings":"AAOA;;;;;;;GAOG;AACH,eAAO,MAAM,kCAAkC,QAAgB,CAAC"}
@@ -0,0 +1,16 @@
1
+ import "node:path";
2
+ import "node:url";
3
+ import.meta.url;
4
+ //#region src/core/identity/provider/account/constants.ts
5
+ /**
6
+ * Lifetime of a pending account link (issue #3439).
7
+ *
8
+ * The handle is redeemed by the very next page load, so it needs to cover a
9
+ * redirect and a bootstrap, not a user's attention span. The authorization
10
+ * state's 30 minutes would leave a redeemable credential-binding handle
11
+ * lying in browser history far longer than the flow that produced it.
12
+ */ const IDENTITY_PROVIDER_ACCOUNT_LINK_TTL = 3e5;
13
+ //#endregion
14
+ export { IDENTITY_PROVIDER_ACCOUNT_LINK_TTL };
15
+
16
+ //# sourceMappingURL=constants.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.mjs","names":["IDENTITY_PROVIDER_ACCOUNT_LINK_TTL"],"sources":["../../../../../src/core/identity/provider/account/constants.ts"],"sourcesContent":["/*\n * Copyright (c) 2026.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\n/**\n * Lifetime of a pending account link (issue #3439).\n *\n * The handle is redeemed by the very next page load, so it needs to cover a\n * redirect and a bootstrap, not a user's attention span. The authorization\n * state's 30 minutes would leave a redeemable credential-binding handle\n * lying in browser history far longer than the flow that produced it.\n */\nexport const IDENTITY_PROVIDER_ACCOUNT_LINK_TTL = 1000 * 60 * 5;\n"],"mappings":";;;;;;;;;;;GAeA,MAAaA,qCAAqC"}
@@ -1,3 +1,4 @@
1
+ export * from './constants.ts';
1
2
  export * from './error.ts';
2
3
  export * from './module.ts';
3
4
  export * from './types.ts';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/core/identity/provider/account/index.ts"],"names":[],"mappings":"AAOA,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/core/identity/provider/account/index.ts"],"names":[],"mappings":"AAOA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC"}
@@ -1,6 +1,7 @@
1
1
  import "node:path";
2
2
  import "node:url";
3
3
  import.meta.url;
4
+ import { IDENTITY_PROVIDER_ACCOUNT_LINK_TTL } from "./constants.mjs";
4
5
  import { IDENTITY_PROVIDER_ACCOUNT_ALREADY_LINKED_ERROR_INSTANCE, IdentityProviderAccountAlreadyLinkedError, isIdentityProviderAccountAlreadyLinkedError } from "./error.mjs";
5
6
  import { IdentityProviderAccountManager } from "./module.mjs";
6
- export { IDENTITY_PROVIDER_ACCOUNT_ALREADY_LINKED_ERROR_INSTANCE, IdentityProviderAccountAlreadyLinkedError, IdentityProviderAccountManager, isIdentityProviderAccountAlreadyLinkedError };
7
+ export { IDENTITY_PROVIDER_ACCOUNT_ALREADY_LINKED_ERROR_INSTANCE, IDENTITY_PROVIDER_ACCOUNT_LINK_TTL, IdentityProviderAccountAlreadyLinkedError, IdentityProviderAccountManager, isIdentityProviderAccountAlreadyLinkedError };
@@ -4,6 +4,41 @@ import type { IIdentityProviderMapper } from '../mapper/index.ts';
4
4
  import type { IdentityProviderIdentity } from '../types.ts';
5
5
  import type { IIdentityProviderAccountRepository } from '../../../entities/identity-provider-account/types.ts';
6
6
  export type { IIdentityProviderAccountRepository } from '../../../entities/identity-provider-account/types.ts';
7
+ /**
8
+ * A resolved external identity awaiting a bearer-authenticated confirmation
9
+ * (issue #3439). The callback that resolved it is unauthenticated, so it may
10
+ * not perform the credential binding itself; it stashes this projection under
11
+ * a one-time handle and the account console redeems it with its bearer.
12
+ *
13
+ * Deliberately four scalars rather than the `IdentityProviderIdentity` it was
14
+ * projected from: that object carries the full provider entity (including the
15
+ * EA-loaded `clientSecret`) and the raw external token payload, neither of
16
+ * which belongs in a cache. They are also exactly what `link()` reads.
17
+ */
18
+ export type IdentityProviderAccountLink = {
19
+ providerId: string;
20
+ /**
21
+ * The user the link-request was minted for. The confirm endpoint
22
+ * requires it to equal the AUTHENTICATED user, which is what stops an
23
+ * attacker-minted handle from binding a victim's external identity to
24
+ * the attacker's account.
25
+ */
26
+ userId: string;
27
+ providerUserId: string;
28
+ providerUserName?: string | null;
29
+ providerUserEmail?: string | null;
30
+ };
31
+ export interface IIdentityProviderAccountLinkStore {
32
+ /**
33
+ * @returns the one-time handle
34
+ */
35
+ save(data: IdentityProviderAccountLink): Promise<string>;
36
+ /**
37
+ * Reads and DROPS the stash. Single use: a handle that reaches a log or
38
+ * a browser history entry must not be redeemable twice.
39
+ */
40
+ consume(handle: string): Promise<IdentityProviderAccountLink | null>;
41
+ }
7
42
  export type IdentityProviderAccountManagerContext = {
8
43
  attributeMapper: IIdentityProviderMapper;
9
44
  permissionMapper: IIdentityProviderMapper;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../../src/core/identity/provider/account/types.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAC;AAChE,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AACvE,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC;AAClE,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAC;AAG5D,OAAO,KAAK,EAAE,kCAAkC,EAAE,MAAM,sDAAsD,CAAC;AAE/G,YAAY,EAAE,kCAAkC,EAAE,MAAM,sDAAsD,CAAC;AAE/G,MAAM,MAAM,qCAAqC,GAAG;IAChD,eAAe,EAAE,uBAAuB,CAAC;IACzC,gBAAgB,EAAE,uBAAuB,CAAC;IAC1C,UAAU,EAAE,uBAAuB,CAAC;IAEpC,UAAU,EAAE,kCAAkC,CAAC;IAC/C,cAAc,EAAE,uBAAuB,CAAA;CAC1C,CAAC;AAEF,MAAM,WAAW,+BAA+B;IAC5C;;;;OAIG;IACH,IAAI,CAAC,QAAQ,EAAE,wBAAwB,GAAI,OAAO,CAAC,uBAAuB,CAAC,CAAC;IAE5E;;;;;;;;OAQG;IACH,IAAI,CAAC,QAAQ,EAAE,wBAAwB,EAAE,MAAM,EAAE,MAAM,GAAI,OAAO,CAAC,uBAAuB,CAAC,CAAC;CAC/F"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../../src/core/identity/provider/account/types.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAC;AAChE,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AACvE,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC;AAClE,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAC;AAG5D,OAAO,KAAK,EAAE,kCAAkC,EAAE,MAAM,sDAAsD,CAAC;AAE/G,YAAY,EAAE,kCAAkC,EAAE,MAAM,sDAAsD,CAAC;AAE/G;;;;;;;;;;GAUG;AACH,MAAM,MAAM,2BAA2B,GAAG;IACtC,UAAU,EAAE,MAAM,CAAC;IACnB;;;;;OAKG;IACH,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,EAAE,MAAM,CAAC;IACvB,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACrC,CAAC;AAEF,MAAM,WAAW,iCAAiC;IAC9C;;OAEG;IACH,IAAI,CAAC,IAAI,EAAE,2BAA2B,GAAI,OAAO,CAAC,MAAM,CAAC,CAAC;IAE1D;;;OAGG;IACH,OAAO,CAAC,MAAM,EAAE,MAAM,GAAI,OAAO,CAAC,2BAA2B,GAAG,IAAI,CAAC,CAAC;CACzE;AAED,MAAM,MAAM,qCAAqC,GAAG;IAChD,eAAe,EAAE,uBAAuB,CAAC;IACzC,gBAAgB,EAAE,uBAAuB,CAAC;IAC1C,UAAU,EAAE,uBAAuB,CAAC;IAEpC,UAAU,EAAE,kCAAkC,CAAC;IAC/C,cAAc,EAAE,uBAAuB,CAAA;CAC1C,CAAC;AAEF,MAAM,WAAW,+BAA+B;IAC5C;;;;OAIG;IACH,IAAI,CAAC,QAAQ,EAAE,wBAAwB,GAAI,OAAO,CAAC,uBAAuB,CAAC,CAAC;IAE5E;;;;;;;;OAQG;IACH,IAAI,CAAC,QAAQ,EAAE,wBAAwB,EAAE,MAAM,EAAE,MAAM,GAAI,OAAO,CAAC,uBAAuB,CAAC,CAAC;CAC/F"}
@@ -1,5 +1,7 @@
1
1
  import type { OAuth2IdentityProvider, OpenIDIdentityProvider, User } from '@authup/core-kit';
2
2
  import type { Result } from '@authup/kit';
3
+ import type { JWTClaims } from '@authup/specs';
4
+ import type { Logger } from '@authup/server-kit';
3
5
  import type { AuthorizeParameters, TokenGrantResponse } from '@hapic/oauth2';
4
6
  import { OAuth2Client } from '@hapic/oauth2';
5
7
  import type { IIdentityProviderAccountManager } from '../../../account/index.ts';
@@ -10,11 +12,27 @@ export declare class IdentityProviderOAuth2Authenticator implements IOAuth2Authe
10
12
  protected options: IdentityProviderOAuth2AuthenticatorOptions;
11
13
  protected accountManager: IIdentityProviderAccountManager;
12
14
  protected provider: OAuth2IdentityProvider | OpenIDIdentityProvider;
15
+ protected logger?: Logger;
13
16
  constructor(ctx: IdentityProviderOAuth2AuthenticatorContext);
14
17
  buildRedirectURL(parameters?: Partial<AuthorizeParameters>): string;
15
18
  resolveIdentity(params: OAuth2AuthorizationCodeGrantPayload): Promise<IdentityProviderIdentity>;
16
19
  authenticate(params: OAuth2AuthorizationCodeGrantPayload): Promise<User>;
17
20
  safeAuthenticate(params: OAuth2AuthorizationCodeGrantPayload): Promise<Result<User>>;
21
+ /**
22
+ * The claims an external identity is described by, richest source last.
23
+ *
24
+ * The access token is opaque by contract (OIDC Core §2), so it is only
25
+ * the floor: authup's own carries `sub`, `kind` and `realm_name` and no
26
+ * username at all, which is why a federated user used to be provisioned
27
+ * under the remote subject UUID.
28
+ */
29
+ protected resolveClaims(input: TokenGrantResponse, payload: JWTClaims): Promise<JWTClaims>;
30
+ /**
31
+ * hapic passes no `signal` to `fetch`, so an endpoint that accepts the
32
+ * connection and never answers would hold the login for undici's 300s
33
+ * headers timeout. Enrichment must not outlast the request it enriches.
34
+ */
35
+ protected withTimeout<T>(promise: Promise<T>): Promise<T>;
18
36
  protected buildIdentityWithTokenGrantResponse(input: TokenGrantResponse): Promise<IdentityProviderIdentity>;
19
37
  }
20
38
  //# sourceMappingURL=module.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../../../../../../../src/core/identity/provider/authentication/protocols/oauth2/module.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,sBAAsB,EAAE,sBAAsB,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAG7F,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C,OAAO,KAAK,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAC7E,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,KAAK,EAAE,+BAA+B,EAAE,MAAM,2BAA2B,CAAC;AACjF,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAC;AAClE,OAAO,KAAK,EACR,oBAAoB,EACpB,0CAA0C,EAC1C,0CAA0C,EAC1C,mCAAmC,EACtC,MAAM,YAAY,CAAC;AAEpB,qBAAa,mCAAoC,YAAW,oBAAoB,CAAC,IAAI,CAAC;IAClF,SAAS,CAAC,MAAM,EAAG,YAAY,CAAC;IAEhC,SAAS,CAAC,OAAO,EAAG,0CAA0C,CAAC;IAE/D,SAAS,CAAC,cAAc,EAAE,+BAA+B,CAAC;IAE1D,SAAS,CAAC,QAAQ,EAAG,sBAAsB,GAAG,sBAAsB,CAAC;gBAIzD,GAAG,EAAE,0CAA0C;IAoB3D,gBAAgB,CAAC,UAAU,GAAE,OAAO,CAAC,mBAAmB,CAAM,GAAI,MAAM;IAYlE,eAAe,CAAC,MAAM,EAAE,mCAAmC,GAAG,OAAO,CAAC,wBAAwB,CAAC;IAW/F,YAAY,CAAC,MAAM,EAAE,mCAAmC,GAAG,OAAO,CAAC,IAAI,CAAC;IAQxE,gBAAgB,CAAC,MAAM,EAAE,mCAAmC,GAAG,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;cAiB1E,mCAAmC,CAAC,KAAK,EAAE,kBAAkB,GAAI,OAAO,CAAC,wBAAwB,CAAC;CAiBrH"}
1
+ {"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../../../../../../../src/core/identity/provider/authentication/protocols/oauth2/module.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,sBAAsB,EAAE,sBAAsB,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAG7F,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAEjD,OAAO,KAAK,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAC7E,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,KAAK,EAAE,+BAA+B,EAAE,MAAM,2BAA2B,CAAC;AACjF,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAC;AAClE,OAAO,KAAK,EACR,oBAAoB,EACpB,0CAA0C,EAC1C,0CAA0C,EAC1C,mCAAmC,EACtC,MAAM,YAAY,CAAC;AAQpB,qBAAa,mCAAoC,YAAW,oBAAoB,CAAC,IAAI,CAAC;IAClF,SAAS,CAAC,MAAM,EAAG,YAAY,CAAC;IAEhC,SAAS,CAAC,OAAO,EAAG,0CAA0C,CAAC;IAE/D,SAAS,CAAC,cAAc,EAAE,+BAA+B,CAAC;IAE1D,SAAS,CAAC,QAAQ,EAAG,sBAAsB,GAAG,sBAAsB,CAAC;IAErE,SAAS,CAAC,MAAM,CAAC,EAAG,MAAM,CAAC;gBAIf,GAAG,EAAE,0CAA0C;IAqB3D,gBAAgB,CAAC,UAAU,GAAE,OAAO,CAAC,mBAAmB,CAAM,GAAI,MAAM;IAYlE,eAAe,CAAC,MAAM,EAAE,mCAAmC,GAAG,OAAO,CAAC,wBAAwB,CAAC;IAW/F,YAAY,CAAC,MAAM,EAAE,mCAAmC,GAAG,OAAO,CAAC,IAAI,CAAC;IAQxE,gBAAgB,CAAC,MAAM,EAAE,mCAAmC,GAAG,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAiB1F;;;;;;;OAOG;cACa,aAAa,CAAC,KAAK,EAAE,kBAAkB,EAAE,OAAO,EAAE,SAAS,GAAI,OAAO,CAAC,SAAS,CAAC;IAyDjG;;;;OAIG;IACH,SAAS,CAAC,WAAW,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,GAAI,OAAO,CAAC,CAAC,CAAC;cAY1C,mCAAmC,CAAC,KAAK,EAAE,kBAAkB,GAAI,OAAO,CAAC,wBAAwB,CAAC;CA2BrH"}
@@ -6,15 +6,21 @@ import { extractTokenPayload } from "@authup/server-kit";
6
6
  import { ValidationError } from "@authup/errors";
7
7
  import { OAuth2Client } from "@hapic/oauth2";
8
8
  //#region src/core/identity/provider/authentication/protocols/oauth2/module.ts
9
+ /**
10
+ * Bound on the optional userinfo enrichment. Short by design: the caller is
11
+ * a browser sitting on a redirect, and the login proceeds without it.
12
+ */ const USERINFO_TIMEOUT = 5e3;
9
13
  var IdentityProviderOAuth2Authenticator = class {
10
14
  client;
11
15
  options;
12
16
  accountManager;
13
17
  provider;
18
+ logger;
14
19
  constructor(ctx) {
15
20
  this.options = ctx.options;
16
21
  this.accountManager = ctx.accountManager;
17
22
  this.provider = ctx.provider;
23
+ this.logger = ctx.logger;
18
24
  this.client = new OAuth2Client({ options: {
19
25
  clientId: ctx.provider.clientId,
20
26
  clientSecret: ctx.provider.clientSecret,
@@ -55,13 +61,60 @@ var IdentityProviderOAuth2Authenticator = class {
55
61
  };
56
62
  }
57
63
  }
64
+ /**
65
+ * The claims an external identity is described by, richest source last.
66
+ *
67
+ * The access token is opaque by contract (OIDC Core §2), so it is only
68
+ * the floor: authup's own carries `sub`, `kind` and `realm_name` and no
69
+ * username at all, which is why a federated user used to be provisioned
70
+ * under the remote subject UUID.
71
+ */ async resolveClaims(input, payload) {
72
+ let claims = payload;
73
+ if (typeof input.id_token === "string") try {
74
+ claims = {
75
+ ...claims,
76
+ ...extractTokenPayload(input.id_token)
77
+ };
78
+ } catch (e) {
79
+ this.logger?.warn(`The identity provider (${this.provider.id}) id_token could not be read: ${e.message}`);
80
+ }
81
+ if (this.provider.userInfoUrl) try {
82
+ const userInfo = await this.withTimeout(this.client.userInfo.get({
83
+ type: "Bearer",
84
+ token: input.access_token
85
+ }));
86
+ if (typeof userInfo.sub === "string" && typeof payload.sub === "string" && userInfo.sub !== payload.sub) this.logger?.warn(`The identity provider (${this.provider.id}) userinfo subject does not match the token subject.`);
87
+ else claims = {
88
+ ...claims,
89
+ ...userInfo
90
+ };
91
+ } catch (e) {
92
+ this.logger?.warn(`The identity provider (${this.provider.id}) userinfo request failed: ${e.message}`);
93
+ }
94
+ return claims;
95
+ }
96
+ /**
97
+ * hapic passes no `signal` to `fetch`, so an endpoint that accepts the
98
+ * connection and never answers would hold the login for undici's 300s
99
+ * headers timeout. Enrichment must not outlast the request it enriches.
100
+ */ withTimeout(promise) {
101
+ return Promise.race([promise, new Promise((_resolve, reject) => {
102
+ setTimeout(() => reject(/* @__PURE__ */ new Error(`the request exceeded ${USERINFO_TIMEOUT}ms`)), USERINFO_TIMEOUT).unref();
103
+ })]);
104
+ }
58
105
  async buildIdentityWithTokenGrantResponse(input) {
59
106
  const payload = extractTokenPayload(input.access_token);
107
+ const claims = await this.resolveClaims(input, payload);
60
108
  return {
61
109
  id: payload.sub,
62
110
  attributeCandidates: {
63
- name: [payload.sub],
64
- email: [payload.email]
111
+ name: [
112
+ claims.preferred_username,
113
+ claims.nickname,
114
+ claims.name,
115
+ claims.sub
116
+ ],
117
+ email: [claims.email]
65
118
  },
66
119
  data: payload,
67
120
  provider: this.provider
@@ -1 +1 @@
1
- {"version":3,"file":"module.mjs","names":["buildIdentityProviderAuthorizeCallbackPath","ValidationError","extractTokenPayload","OAuth2Client","IdentityProviderOAuth2Authenticator","client","options","accountManager","provider","ctx","clientId","clientSecret","redirectUri","baseURL","id","scope","undefined","authorizationEndpoint","authorizeUrl","tokenEndpoint","tokenUrl","userinfoEndpoint","userInfoUrl","buildRedirectURL","parameters","authorize","buildURL","resolveIdentity","params","token","createWithAuthorizationCode","identity","buildIdentityWithTokenGrantResponse","authenticate","account","save","user","safeAuthenticate","data","success","e","error","input","payload","access_token","sub","attributeCandidates","name","email"],"sources":["../../../../../../../src/core/identity/provider/authentication/protocols/oauth2/module.ts"],"sourcesContent":["/*\n * Copyright (c) 2023-2023.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport type { OAuth2IdentityProvider, OpenIDIdentityProvider, User } from '@authup/core-kit';\nimport { buildIdentityProviderAuthorizeCallbackPath } from '@authup/core-kit';\nimport { ValidationError } from '@authup/errors';\nimport type { Result } from '@authup/kit';\nimport { extractTokenPayload } from '@authup/server-kit';\nimport type { AuthorizeParameters, TokenGrantResponse } from '@hapic/oauth2';\nimport { OAuth2Client } from '@hapic/oauth2';\nimport type { IIdentityProviderAccountManager } from '../../../account/index.ts';\nimport type { IdentityProviderIdentity } from '../../../types.ts';\nimport type {\n IOAuth2Authenticator,\n IdentityProviderOAuth2AuthenticatorContext,\n IdentityProviderOAuth2AuthenticatorOptions,\n OAuth2AuthorizationCodeGrantPayload,\n} from './types.ts';\n\nexport class IdentityProviderOAuth2Authenticator implements IOAuth2Authenticator<User> {\n protected client : OAuth2Client;\n\n protected options : IdentityProviderOAuth2AuthenticatorOptions;\n\n protected accountManager: IIdentityProviderAccountManager;\n\n protected provider : OAuth2IdentityProvider | OpenIDIdentityProvider;\n\n //----------------------------------------------------------------------\n\n constructor(ctx: IdentityProviderOAuth2AuthenticatorContext) {\n this.options = ctx.options;\n this.accountManager = ctx.accountManager;\n this.provider = ctx.provider;\n\n this.client = new OAuth2Client({\n options: {\n clientId: ctx.provider.clientId,\n clientSecret: ctx.provider.clientSecret,\n redirectUri: `${ctx.options.baseURL}${buildIdentityProviderAuthorizeCallbackPath(ctx.provider.id)}`,\n scope: ctx.provider.scope || undefined,\n authorizationEndpoint: ctx.provider.authorizeUrl,\n tokenEndpoint: ctx.provider.tokenUrl,\n userinfoEndpoint: ctx.provider.userInfoUrl || undefined,\n },\n });\n }\n\n //----------------------------------------------------------------------\n\n buildRedirectURL(parameters: Partial<AuthorizeParameters> = {}) : string {\n try {\n return this.client.authorize.buildURL(parameters);\n } catch {\n throw new ValidationError(\n 'The identity provider is misconfigured and has an invalid or missing authorize URL.',\n );\n }\n }\n\n //----------------------------------------------------------------------\n\n async resolveIdentity(params: OAuth2AuthorizationCodeGrantPayload): Promise<IdentityProviderIdentity> {\n const token = await this.client.token.createWithAuthorizationCode(params);\n\n const identity = await this.buildIdentityWithTokenGrantResponse(token);\n if (this.options.clientId) {\n identity.clientId = this.options.clientId;\n }\n\n return identity;\n }\n\n async authenticate(params: OAuth2AuthorizationCodeGrantPayload): Promise<User> {\n const identity = await this.resolveIdentity(params);\n\n const account = await this.accountManager.save(identity);\n\n return account.user;\n }\n\n async safeAuthenticate(params: OAuth2AuthorizationCodeGrantPayload): Promise<Result<User>> {\n try {\n const data = await this.authenticate(params);\n return {\n success: true,\n data, \n };\n } catch (e) {\n return {\n success: false,\n error: e as Error, \n };\n }\n }\n\n //----------------------------------------------------------------------\n\n protected async buildIdentityWithTokenGrantResponse(input: TokenGrantResponse) : Promise<IdentityProviderIdentity> {\n const payload = extractTokenPayload(input.access_token);\n\n return {\n id: payload.sub!,\n attributeCandidates: {\n name: [\n payload.sub,\n ],\n email: [\n payload.email,\n ],\n },\n data: payload,\n provider: this.provider,\n };\n }\n}\n"],"mappings":";;;;;;;;AAuBA,IAAaI,sCAAb,MAAaA;CACCC;CAEAC;CAEAC;CAEAC;CAIV,YAAYC,KAAiD;EACzD,KAAKH,UAAUG,IAAIH;EACnB,KAAKC,iBAAiBE,IAAIF;EAC1B,KAAKC,WAAWC,IAAID;EAEpB,KAAKH,SAAS,IAAIF,aAAa,EAC3BG,SAAS;GACLI,UAAUD,IAAID,SAASE;GACvBC,cAAcF,IAAID,SAASG;GAC3BC,aAAa,GAAGH,IAAIH,QAAQO,UAAUb,2CAA2CS,IAAID,SAASM,EAAE;GAChGC,OAAON,IAAID,SAASO,SAASC,KAAAA;GAC7BC,uBAAuBR,IAAID,SAASU;GACpCC,eAAeV,IAAID,SAASY;GAC5BC,kBAAkBZ,IAAID,SAASc,eAAeN,KAAAA;EAClD,EACJ,CAAA;CACJ;CAIAO,iBAAiBC,aAA2C,CAAC,GAAY;EACrE,IAAI;GACA,OAAO,KAAKnB,OAAOoB,UAAUC,SAASF,UAAAA;EAC1C,QAAQ;GACJ,MAAM,IAAIvB,gBACN,qFAAA;EAER;CACJ;CAIA,MAAM0B,gBAAgBC,QAAgF;EAClG,MAAMC,QAAQ,MAAM,KAAKxB,OAAOwB,MAAMC,4BAA4BF,MAAAA;EAElE,MAAMG,WAAW,MAAM,KAAKC,oCAAoCH,KAAAA;EAChE,IAAI,KAAKvB,QAAQI,UACbqB,SAASrB,WAAW,KAAKJ,QAAQI;EAGrC,OAAOqB;CACX;CAEA,MAAME,aAAaL,QAA4D;EAC3E,MAAMG,WAAW,MAAM,KAAKJ,gBAAgBC,MAAAA;EAI5C,QAAOM,MAFe,KAAK3B,eAAe4B,KAAKJ,QAAAA,EAAAA,CAEhCK;CACnB;CAEA,MAAMC,iBAAiBT,QAAoE;EACvF,IAAI;GAEA,OAAO;IACHW,SAAS;IACTD,MAAAA,MAHe,KAAKL,aAAaL,MAAAA;GAIrC;EACJ,SAASY,GAAG;GACR,OAAO;IACHD,SAAS;IACTE,OAAOD;GACX;EACJ;CACJ;CAIA,MAAgBR,oCAAoCU,OAA+D;EAC/G,MAAMC,UAAUzC,oBAAoBwC,MAAME,YAAY;EAEtD,OAAO;GACH9B,IAAI6B,QAAQE;GACZC,qBAAqB;IACjBC,MAAM,CACFJ,QAAQE,GACX;IACDG,OAAO,CACHL,QAAQK,KACX;GACL;GACAV,MAAMK;GACNnC,UAAU,KAAKA;EACnB;CACJ;AACJ"}
1
+ {"version":3,"file":"module.mjs","names":["buildIdentityProviderAuthorizeCallbackPath","ValidationError","extractTokenPayload","OAuth2Client","USERINFO_TIMEOUT","IdentityProviderOAuth2Authenticator","client","options","accountManager","provider","logger","ctx","clientId","clientSecret","redirectUri","baseURL","id","scope","undefined","authorizationEndpoint","authorizeUrl","tokenEndpoint","tokenUrl","userinfoEndpoint","userInfoUrl","buildRedirectURL","parameters","authorize","buildURL","resolveIdentity","params","token","createWithAuthorizationCode","identity","buildIdentityWithTokenGrantResponse","authenticate","account","save","user","safeAuthenticate","data","success","e","error","resolveClaims","input","payload","claims","id_token","warn","message","userInfo","withTimeout","get","type","access_token","sub","promise","Promise","race","_resolve","reject","setTimeout","Error","unref","attributeCandidates","name","preferred_username","nickname","email"],"sources":["../../../../../../../src/core/identity/provider/authentication/protocols/oauth2/module.ts"],"sourcesContent":["/*\n * Copyright (c) 2023-2023.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport type { OAuth2IdentityProvider, OpenIDIdentityProvider, User } from '@authup/core-kit';\nimport { buildIdentityProviderAuthorizeCallbackPath } from '@authup/core-kit';\nimport { ValidationError } from '@authup/errors';\nimport type { Result } from '@authup/kit';\nimport type { JWTClaims } from '@authup/specs';\nimport type { Logger } from '@authup/server-kit';\nimport { extractTokenPayload } from '@authup/server-kit';\nimport type { AuthorizeParameters, TokenGrantResponse } from '@hapic/oauth2';\nimport { OAuth2Client } from '@hapic/oauth2';\nimport type { IIdentityProviderAccountManager } from '../../../account/index.ts';\nimport type { IdentityProviderIdentity } from '../../../types.ts';\nimport type {\n IOAuth2Authenticator,\n IdentityProviderOAuth2AuthenticatorContext,\n IdentityProviderOAuth2AuthenticatorOptions,\n OAuth2AuthorizationCodeGrantPayload,\n} from './types.ts';\n\n/**\n * Bound on the optional userinfo enrichment. Short by design: the caller is\n * a browser sitting on a redirect, and the login proceeds without it.\n */\nconst USERINFO_TIMEOUT = 5000;\n\nexport class IdentityProviderOAuth2Authenticator implements IOAuth2Authenticator<User> {\n protected client : OAuth2Client;\n\n protected options : IdentityProviderOAuth2AuthenticatorOptions;\n\n protected accountManager: IIdentityProviderAccountManager;\n\n protected provider : OAuth2IdentityProvider | OpenIDIdentityProvider;\n\n protected logger? : Logger;\n\n //----------------------------------------------------------------------\n\n constructor(ctx: IdentityProviderOAuth2AuthenticatorContext) {\n this.options = ctx.options;\n this.accountManager = ctx.accountManager;\n this.provider = ctx.provider;\n this.logger = ctx.logger;\n\n this.client = new OAuth2Client({\n options: {\n clientId: ctx.provider.clientId,\n clientSecret: ctx.provider.clientSecret,\n redirectUri: `${ctx.options.baseURL}${buildIdentityProviderAuthorizeCallbackPath(ctx.provider.id)}`,\n scope: ctx.provider.scope || undefined,\n authorizationEndpoint: ctx.provider.authorizeUrl,\n tokenEndpoint: ctx.provider.tokenUrl,\n userinfoEndpoint: ctx.provider.userInfoUrl || undefined,\n },\n });\n }\n\n //----------------------------------------------------------------------\n\n buildRedirectURL(parameters: Partial<AuthorizeParameters> = {}) : string {\n try {\n return this.client.authorize.buildURL(parameters);\n } catch {\n throw new ValidationError(\n 'The identity provider is misconfigured and has an invalid or missing authorize URL.',\n );\n }\n }\n\n //----------------------------------------------------------------------\n\n async resolveIdentity(params: OAuth2AuthorizationCodeGrantPayload): Promise<IdentityProviderIdentity> {\n const token = await this.client.token.createWithAuthorizationCode(params);\n\n const identity = await this.buildIdentityWithTokenGrantResponse(token);\n if (this.options.clientId) {\n identity.clientId = this.options.clientId;\n }\n\n return identity;\n }\n\n async authenticate(params: OAuth2AuthorizationCodeGrantPayload): Promise<User> {\n const identity = await this.resolveIdentity(params);\n\n const account = await this.accountManager.save(identity);\n\n return account.user;\n }\n\n async safeAuthenticate(params: OAuth2AuthorizationCodeGrantPayload): Promise<Result<User>> {\n try {\n const data = await this.authenticate(params);\n return {\n success: true,\n data, \n };\n } catch (e) {\n return {\n success: false,\n error: e as Error, \n };\n }\n }\n\n //----------------------------------------------------------------------\n\n /**\n * The claims an external identity is described by, richest source last.\n *\n * The access token is opaque by contract (OIDC Core §2), so it is only\n * the floor: authup's own carries `sub`, `kind` and `realm_name` and no\n * username at all, which is why a federated user used to be provisioned\n * under the remote subject UUID.\n */\n protected async resolveClaims(input: TokenGrantResponse, payload: JWTClaims) : Promise<JWTClaims> {\n let claims = payload;\n\n if (typeof input.id_token === 'string') {\n try {\n claims = {\n ...claims,\n ...extractTokenPayload(input.id_token),\n };\n } catch (e) {\n // an encrypted (five-segment JWE) id_token is not decodable\n // here, and was ignored outright before it was read at all.\n // Logged rather than swallowed silently: every other reason\n // to land here leaves the user provisioned under the remote\n // subject, which is the defect this method exists to fix.\n this.logger?.warn(\n `The identity provider (${this.provider.id}) id_token could not be read: ${(e as Error).message}`,\n );\n }\n }\n\n if (this.provider.userInfoUrl) {\n // the guard is load-bearing: the client carries no baseURL, so\n // hapic's `/userinfo` default would be a relative fetch URL\n try {\n const userInfo = await this.withTimeout(this.client.userInfo.get({\n type: 'Bearer',\n token: input.access_token,\n }));\n\n // OIDC Core 5.3.2: a userinfo response whose `sub` does not\n // match the token's MUST NOT be used. Without this a\n // mis-routed response (a multi-tenant gateway, a token\n // mix-up) would name and, worse, EMAIL the local user after\n // somebody else.\n if (\n typeof userInfo.sub === 'string' &&\n typeof payload.sub === 'string' &&\n userInfo.sub !== payload.sub\n ) {\n this.logger?.warn(\n `The identity provider (${this.provider.id}) userinfo subject does not match the token subject.`,\n );\n } else {\n claims = { ...claims, ...userInfo };\n }\n } catch (e) {\n // enrichment, never a login blocker\n this.logger?.warn(\n `The identity provider (${this.provider.id}) userinfo request failed: ${(e as Error).message}`,\n );\n }\n }\n\n return claims;\n }\n\n /**\n * hapic passes no `signal` to `fetch`, so an endpoint that accepts the\n * connection and never answers would hold the login for undici's 300s\n * headers timeout. Enrichment must not outlast the request it enriches.\n */\n protected withTimeout<T>(promise: Promise<T>) : Promise<T> {\n return Promise.race([\n promise,\n new Promise<T>((_resolve, reject) => {\n setTimeout(\n () => reject(new Error(`the request exceeded ${USERINFO_TIMEOUT}ms`)),\n USERINFO_TIMEOUT,\n ).unref();\n }),\n ]);\n }\n\n protected async buildIdentityWithTokenGrantResponse(input: TokenGrantResponse) : Promise<IdentityProviderIdentity> {\n const payload = extractTokenPayload(input.access_token);\n const claims = await this.resolveClaims(input, payload);\n\n return {\n // the account key: sourcing it from a richer claim set would\n // orphan every existing auth_identity_provider_accounts row\n id: payload.sub!,\n attributeCandidates: {\n name: [\n // keycloak/authentik put the username here, authup its\n // (nullable) display name; a candidate failing name\n // validation shifts to the next one\n claims.preferred_username,\n claims.nickname,\n // authup's own id_token: the real user name\n claims.name,\n claims.sub,\n ],\n email: [\n claims.email,\n ],\n },\n data: payload,\n provider: this.provider,\n };\n }\n}\n"],"mappings":";;;;;;;;;;;GA6BA,MAAMI,mBAAmB;AAEzB,IAAaC,sCAAb,MAAaA;CACCC;CAEAC;CAEAC;CAEAC;CAEAC;CAIV,YAAYC,KAAiD;EACzD,KAAKJ,UAAUI,IAAIJ;EACnB,KAAKC,iBAAiBG,IAAIH;EAC1B,KAAKC,WAAWE,IAAIF;EACpB,KAAKC,SAASC,IAAID;EAElB,KAAKJ,SAAS,IAAIH,aAAa,EAC3BI,SAAS;GACLK,UAAUD,IAAIF,SAASG;GACvBC,cAAcF,IAAIF,SAASI;GAC3BC,aAAa,GAAGH,IAAIJ,QAAQQ,UAAUf,2CAA2CW,IAAIF,SAASO,EAAE;GAChGC,OAAON,IAAIF,SAASQ,SAASC,KAAAA;GAC7BC,uBAAuBR,IAAIF,SAASW;GACpCC,eAAeV,IAAIF,SAASa;GAC5BC,kBAAkBZ,IAAIF,SAASe,eAAeN,KAAAA;EAClD,EACJ,CAAA;CACJ;CAIAO,iBAAiBC,aAA2C,CAAC,GAAY;EACrE,IAAI;GACA,OAAO,KAAKpB,OAAOqB,UAAUC,SAASF,UAAAA;EAC1C,QAAQ;GACJ,MAAM,IAAIzB,gBACN,qFAAA;EAER;CACJ;CAIA,MAAM4B,gBAAgBC,QAAgF;EAClG,MAAMC,QAAQ,MAAM,KAAKzB,OAAOyB,MAAMC,4BAA4BF,MAAAA;EAElE,MAAMG,WAAW,MAAM,KAAKC,oCAAoCH,KAAAA;EAChE,IAAI,KAAKxB,QAAQK,UACbqB,SAASrB,WAAW,KAAKL,QAAQK;EAGrC,OAAOqB;CACX;CAEA,MAAME,aAAaL,QAA4D;EAC3E,MAAMG,WAAW,MAAM,KAAKJ,gBAAgBC,MAAAA;EAI5C,QAAOM,MAFe,KAAK5B,eAAe6B,KAAKJ,QAAAA,EAAAA,CAEhCK;CACnB;CAEA,MAAMC,iBAAiBT,QAAoE;EACvF,IAAI;GAEA,OAAO;IACHW,SAAS;IACTD,MAAAA,MAHe,KAAKL,aAAaL,MAAAA;GAIrC;EACJ,SAASY,GAAG;GACR,OAAO;IACHD,SAAS;IACTE,OAAOD;GACX;EACJ;CACJ;;;;;;;;IAYA,MAAgBE,cAAcC,OAA2BC,SAAyC;EAC9F,IAAIC,SAASD;EAEb,IAAI,OAAOD,MAAMG,aAAa,UAC1B,IAAI;GACAD,SAAS;IACL,GAAGA;IACH,GAAG7C,oBAAoB2C,MAAMG,QAAQ;GACzC;EACJ,SAASN,GAAG;GAMR,KAAKhC,QAAQuC,KACT,0BAA0B,KAAKxC,SAASO,GAAG,gCAAgC,EAAakC,SAAS;EAEzG;EAGJ,IAAI,KAAKzC,SAASe,aAGd,IAAI;GACA,MAAM2B,WAAW,MAAM,KAAKC,YAAY,KAAK9C,OAAO6C,SAASE,IAAI;IAC7DC,MAAM;IACNvB,OAAOc,MAAMU;GACjB,CAAA,CAAA;GAOA,IACI,OAAOJ,SAASK,QAAQ,YACxB,OAAOV,QAAQU,QAAQ,YACvBL,SAASK,QAAQV,QAAQU,KAEzB,KAAK9C,QAAQuC,KACT,0BAA0B,KAAKxC,SAASO,GAAG,qDAAqD;QAGpG+B,SAAS;IAAE,GAAGA;IAAQ,GAAGI;GAAS;EAE1C,SAAST,GAAG;GAER,KAAKhC,QAAQuC,KACT,0BAA0B,KAAKxC,SAASO,GAAG,6BAA6B,EAAakC,SAAS;EAEtG;EAGJ,OAAOH;CACX;;;;;IAOA,YAAyBU,SAAkC;EACvD,OAAOC,QAAQC,KAAK,CAChBF,SACA,IAAIC,SAAYE,UAAUC,WAAAA;GACtBC,iBACUD,uBAAO,IAAIE,MAAM,wBAAwB3D,iBAAiB,GAAG,CAAA,GACnEA,gBAAAA,CAAAA,CACF4D,MAAK;EACX,CAAA,CACH,CAAA;CACL;CAEA,MAAgB9B,oCAAoCW,OAA+D;EAC/G,MAAMC,UAAU5C,oBAAoB2C,MAAMU,YAAY;EACtD,MAAMR,SAAS,MAAM,KAAKH,cAAcC,OAAOC,OAAAA;EAE/C,OAAO;GAGH9B,IAAI8B,QAAQU;GACZS,qBAAqB;IACjBC,MAAM;KAIFnB,OAAOoB;KACPpB,OAAOqB;KAEPrB,OAAOmB;KACPnB,OAAOS;IACV;IACDa,OAAO,CACHtB,OAAOsB,KACV;GACL;GACA7B,MAAMM;GACNrC,UAAU,KAAKA;EACnB;CACJ;AACJ"}
@@ -1,5 +1,6 @@
1
1
  import type { OAuth2IdentityProvider, OpenIDIdentityProvider } from '@authup/core-kit';
2
2
  import type { ObjectLiteral, Result } from '@authup/kit';
3
+ import type { Logger } from '@authup/server-kit';
3
4
  import type { AuthorizeParameters } from '@hapic/oauth2';
4
5
  import type { IIdentityProviderAccountManager } from '../../../account/index.ts';
5
6
  import type { IdentityProviderIdentity } from '../../../types.ts';
@@ -26,5 +27,6 @@ export type IdentityProviderOAuth2AuthenticatorContext = {
26
27
  options: IdentityProviderOAuth2AuthenticatorOptions;
27
28
  accountManager: IIdentityProviderAccountManager;
28
29
  provider: OAuth2IdentityProvider | OpenIDIdentityProvider;
30
+ logger?: Logger;
29
31
  };
30
32
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../../../../src/core/identity/provider/authentication/protocols/oauth2/types.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,sBAAsB,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AACvF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AACzD,OAAO,KAAK,EAAE,+BAA+B,EAAE,MAAM,2BAA2B,CAAC;AACjF,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAC;AAElE,MAAM,MAAM,mCAAmC,GAAG;IAC9C,IAAI,EAAE,MAAM,CAAA;IACZ,aAAa,CAAC,EAAE,MAAM,CAAA;CACzB,CAAC;AAEF,MAAM,WAAW,oBAAoB,CAAC,CAAC,SAAS,aAAa,GAAG,aAAa;IACzE,YAAY,CAAC,MAAM,EAAE,mCAAmC,GAAI,OAAO,CAAC,CAAC,CAAC,CAAC;IAEvE,gBAAgB,CAAC,MAAM,EAAE,mCAAmC,GAAI,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;IAEnF;;;;OAIG;IACH,eAAe,CAAC,MAAM,EAAE,mCAAmC,GAAI,OAAO,CAAC,wBAAwB,CAAC,CAAC;IAEjG,gBAAgB,CAAC,UAAU,CAAC,EAAE,OAAO,CAAC,mBAAmB,CAAC,GAAG,MAAM,CAAC;CACvE;AAED,MAAM,MAAM,0CAA0C,GAAG;IACrD,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAA;CACpB,CAAC;AAEF,MAAM,MAAM,0CAA0C,GAAG;IACrD,OAAO,EAAE,0CAA0C,CAAC;IACpD,cAAc,EAAE,+BAA+B,CAAA;IAC/C,QAAQ,EAAE,sBAAsB,GAAG,sBAAsB,CAAC;CAC7D,CAAC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../../../../src/core/identity/provider/authentication/protocols/oauth2/types.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,sBAAsB,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AACvF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AACzD,OAAO,KAAK,EAAE,+BAA+B,EAAE,MAAM,2BAA2B,CAAC;AACjF,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAC;AAElE,MAAM,MAAM,mCAAmC,GAAG;IAC9C,IAAI,EAAE,MAAM,CAAA;IACZ,aAAa,CAAC,EAAE,MAAM,CAAA;CACzB,CAAC;AAEF,MAAM,WAAW,oBAAoB,CAAC,CAAC,SAAS,aAAa,GAAG,aAAa;IACzE,YAAY,CAAC,MAAM,EAAE,mCAAmC,GAAI,OAAO,CAAC,CAAC,CAAC,CAAC;IAEvE,gBAAgB,CAAC,MAAM,EAAE,mCAAmC,GAAI,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;IAEnF;;;;OAIG;IACH,eAAe,CAAC,MAAM,EAAE,mCAAmC,GAAI,OAAO,CAAC,wBAAwB,CAAC,CAAC;IAEjG,gBAAgB,CAAC,UAAU,CAAC,EAAE,OAAO,CAAC,mBAAmB,CAAC,GAAG,MAAM,CAAC;CACvE;AAED,MAAM,MAAM,0CAA0C,GAAG;IACrD,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAA;CACpB,CAAC;AAEF,MAAM,MAAM,0CAA0C,GAAG;IACrD,OAAO,EAAE,0CAA0C,CAAC;IACpD,cAAc,EAAE,+BAA+B,CAAA;IAC/C,QAAQ,EAAE,sBAAsB,GAAG,sBAAsB,CAAC;IAC1D,MAAM,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC"}
@@ -1,9 +1,6 @@
1
- import type { TokenGrantResponse } from '@hapic/oauth2';
2
- import type { IdentityProviderIdentity } from '../../../types.ts';
3
1
  import type { IdentityProviderOAuth2AuthenticatorContext } from '../oauth2/index.ts';
4
2
  import { IdentityProviderOAuth2Authenticator } from '../oauth2/index.ts';
5
3
  export declare class IdentityProviderOpenIDAuthenticator extends IdentityProviderOAuth2Authenticator {
6
4
  constructor(ctx: IdentityProviderOAuth2AuthenticatorContext);
7
- protected buildIdentityWithTokenGrantResponse(input: TokenGrantResponse): Promise<IdentityProviderIdentity>;
8
5
  }
9
6
  //# sourceMappingURL=module.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../../../../../../../src/core/identity/provider/authentication/protocols/open-id/module.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACxD,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAC;AAClE,OAAO,KAAK,EAAE,0CAA0C,EAAE,MAAM,oBAAoB,CAAC;AACrF,OAAO,EAAE,mCAAmC,EAAE,MAAM,oBAAoB,CAAC;AAEzE,qBAAa,mCAAoC,SAAQ,mCAAmC;gBAC5E,GAAG,EAAE,0CAA0C;cAU3C,mCAAmC,CAAC,KAAK,EAAE,kBAAkB,GAAG,OAAO,CAAC,wBAAwB,CAAC;CAmBpH"}
1
+ {"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../../../../../../../src/core/identity/provider/authentication/protocols/open-id/module.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,0CAA0C,EAAE,MAAM,oBAAoB,CAAC;AACrF,OAAO,EAAE,mCAAmC,EAAE,MAAM,oBAAoB,CAAC;AAEzE,qBAAa,mCAAoC,SAAQ,mCAAmC;gBAC5E,GAAG,EAAE,0CAA0C;CAS9D"}
@@ -3,7 +3,6 @@ import "node:url";
3
3
  import.meta.url;
4
4
  import { IdentityProviderOAuth2Authenticator } from "../oauth2/module.mjs";
5
5
  import "../oauth2/index.mjs";
6
- import { extractTokenPayload } from "@authup/server-kit";
7
6
  import { mergeOAuth2Scopes } from "@authup/specs";
8
7
  //#region src/core/identity/provider/authentication/protocols/open-id/module.ts
9
8
  var IdentityProviderOpenIDAuthenticator = class extends IdentityProviderOAuth2Authenticator {
@@ -11,22 +10,6 @@ var IdentityProviderOpenIDAuthenticator = class extends IdentityProviderOAuth2Au
11
10
  ctx.provider.scope = mergeOAuth2Scopes("openid", ctx.provider.scope || "openid profile email");
12
11
  super(ctx);
13
12
  }
14
- async buildIdentityWithTokenGrantResponse(input) {
15
- const payload = extractTokenPayload(input.access_token);
16
- return {
17
- id: payload.sub,
18
- attributeCandidates: {
19
- name: [
20
- payload.preferred_username,
21
- payload.nickname,
22
- payload.sub
23
- ],
24
- email: [payload.email]
25
- },
26
- data: payload,
27
- provider: this.provider
28
- };
29
- }
30
13
  };
31
14
  //#endregion
32
15
  export { IdentityProviderOpenIDAuthenticator };
@@ -1 +1 @@
1
- {"version":3,"file":"module.mjs","names":["extractTokenPayload","mergeOAuth2Scopes","IdentityProviderOAuth2Authenticator","IdentityProviderOpenIDAuthenticator","ctx","provider","scope","buildIdentityWithTokenGrantResponse","input","payload","access_token","id","sub","attributeCandidates","name","preferred_username","nickname","email","data"],"sources":["../../../../../../../src/core/identity/provider/authentication/protocols/open-id/module.ts"],"sourcesContent":["/*\n * Copyright (c) 2023-2025.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport { extractTokenPayload } from '@authup/server-kit';\nimport { mergeOAuth2Scopes } from '@authup/specs';\nimport type { TokenGrantResponse } from '@hapic/oauth2';\nimport type { IdentityProviderIdentity } from '../../../types.ts';\nimport type { IdentityProviderOAuth2AuthenticatorContext } from '../oauth2/index.ts';\nimport { IdentityProviderOAuth2Authenticator } from '../oauth2/index.ts';\n\nexport class IdentityProviderOpenIDAuthenticator extends IdentityProviderOAuth2Authenticator {\n constructor(ctx: IdentityProviderOAuth2AuthenticatorContext) {\n // OIDC requires the openid scope (Core §3.1.2.1)\n ctx.provider.scope = mergeOAuth2Scopes(\n 'openid',\n ctx.provider.scope || 'openid profile email',\n );\n\n super(ctx);\n }\n\n protected async buildIdentityWithTokenGrantResponse(input: TokenGrantResponse): Promise<IdentityProviderIdentity> {\n const payload = extractTokenPayload(input.access_token);\n\n return {\n id: payload.sub!,\n attributeCandidates: {\n name: [\n payload.preferred_username,\n payload.nickname,\n payload.sub,\n ],\n email: [\n payload.email,\n ],\n },\n data: payload,\n provider: this.provider,\n };\n }\n}\n"],"mappings":";;;;;;;;AAcA,IAAaG,sCAAb,cAAyDD,oCAAAA;CACrD,YAAYE,KAAiD;EAEzDA,IAAIC,SAASC,QAAQL,kBACjB,UACAG,IAAIC,SAASC,SAAS,sBAAA;EAG1B,MAAMF,GAAAA;CACV;CAEA,MAAgBG,oCAAoCC,OAA8D;EAC9G,MAAMC,UAAUT,oBAAoBQ,MAAME,YAAY;EAEtD,OAAO;GACHC,IAAIF,QAAQG;GACZC,qBAAqB;IACjBC,MAAM;KACFL,QAAQM;KACRN,QAAQO;KACRP,QAAQG;IACX;IACDK,OAAO,CACHR,QAAQQ,KACX;GACL;GACAC,MAAMT;GACNJ,UAAU,KAAKA;EACnB;CACJ;AACJ"}
1
+ {"version":3,"file":"module.mjs","names":["mergeOAuth2Scopes","IdentityProviderOAuth2Authenticator","IdentityProviderOpenIDAuthenticator","ctx","provider","scope"],"sources":["../../../../../../../src/core/identity/provider/authentication/protocols/open-id/module.ts"],"sourcesContent":["/*\n * Copyright (c) 2023-2025.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport { mergeOAuth2Scopes } from '@authup/specs';\nimport type { IdentityProviderOAuth2AuthenticatorContext } from '../oauth2/index.ts';\nimport { IdentityProviderOAuth2Authenticator } from '../oauth2/index.ts';\n\nexport class IdentityProviderOpenIDAuthenticator extends IdentityProviderOAuth2Authenticator {\n constructor(ctx: IdentityProviderOAuth2AuthenticatorContext) {\n // OIDC requires the openid scope (Core §3.1.2.1)\n ctx.provider.scope = mergeOAuth2Scopes(\n 'openid',\n ctx.provider.scope || 'openid profile email',\n );\n\n super(ctx);\n }\n}\n"],"mappings":";;;;;;;AAWA,IAAaE,sCAAb,cAAyDD,oCAAAA;CACrD,YAAYE,KAAiD;EAEzDA,IAAIC,SAASC,QAAQL,kBACjB,UACAG,IAAIC,SAASC,SAAS,sBAAA;EAG1B,MAAMF,GAAAA;CACV;AACJ"}
@@ -1,6 +1,7 @@
1
1
  import "node:path";
2
2
  import "node:url";
3
3
  import.meta.url;
4
+ import { IDENTITY_PROVIDER_ACCOUNT_LINK_TTL } from "./account/constants.mjs";
4
5
  import { IDENTITY_PROVIDER_ACCOUNT_ALREADY_LINKED_ERROR_INSTANCE, IdentityProviderAccountAlreadyLinkedError, isIdentityProviderAccountAlreadyLinkedError } from "./account/error.mjs";
5
6
  import { IdentityProviderMapperOperation } from "./mapper/constants.mjs";
6
7
  import { IdentityProviderAccountBaseMapper } from "./mapper/base.mjs";
@@ -22,4 +23,4 @@ import { IdentityProviderPaypalAuthenticator } from "./authentication/presets/pa
22
23
  import { IDENTITY_PROVIDER_LDAP_COLLECTION_AUTHENTICATOR_TOKEN } from "./authentication/constants.mjs";
23
24
  import { createIdentityProviderOAuth2Authenticator } from "./authentication/factory.mjs";
24
25
  import "./authentication/index.mjs";
25
- export { IDENTITY_PROVIDER_ACCOUNT_ALREADY_LINKED_ERROR_INSTANCE, IDENTITY_PROVIDER_LDAP_COLLECTION_AUTHENTICATOR_TOKEN, IdentityProviderAccountAlreadyLinkedError, IdentityProviderAccountBaseMapper, IdentityProviderAccountManager, IdentityProviderAttributeMapper, IdentityProviderFacebookAuthenticator, IdentityProviderGithubAuthenticator, IdentityProviderGoogleAuthenticator, IdentityProviderInstagramAuthenticator, IdentityProviderLdapAuthenticator, IdentityProviderLdapCollectionAuthenticator, IdentityProviderMapperOperation, IdentityProviderOAuth2Authenticator, IdentityProviderOpenIDAuthenticator, IdentityProviderPaypalAuthenticator, IdentityProviderPermissionMapper, IdentityProviderRoleMapper, createIdentityProviderOAuth2Authenticator, isIdentityProviderAccountAlreadyLinkedError };
26
+ export { IDENTITY_PROVIDER_ACCOUNT_ALREADY_LINKED_ERROR_INSTANCE, IDENTITY_PROVIDER_ACCOUNT_LINK_TTL, IDENTITY_PROVIDER_LDAP_COLLECTION_AUTHENTICATOR_TOKEN, IdentityProviderAccountAlreadyLinkedError, IdentityProviderAccountBaseMapper, IdentityProviderAccountManager, IdentityProviderAttributeMapper, IdentityProviderFacebookAuthenticator, IdentityProviderGithubAuthenticator, IdentityProviderGoogleAuthenticator, IdentityProviderInstagramAuthenticator, IdentityProviderLdapAuthenticator, IdentityProviderLdapCollectionAuthenticator, IdentityProviderMapperOperation, IdentityProviderOAuth2Authenticator, IdentityProviderOpenIDAuthenticator, IdentityProviderPaypalAuthenticator, IdentityProviderPermissionMapper, IdentityProviderRoleMapper, createIdentityProviderOAuth2Authenticator, isIdentityProviderAccountAlreadyLinkedError };
@@ -136,6 +136,7 @@ import { PasswordRecoveryService } from "./identity/password-recovery/service.mj
136
136
  import { PermissionCheckerService } from "./identity/permission/checker/service.mjs";
137
137
  import { IdentityPermissionProvider } from "./identity/permission/module.mjs";
138
138
  import { PolicyCheckerService } from "./identity/policy/checker/service.mjs";
139
+ import { IDENTITY_PROVIDER_ACCOUNT_LINK_TTL } from "./identity/provider/account/constants.mjs";
139
140
  import { IDENTITY_PROVIDER_ACCOUNT_ALREADY_LINKED_ERROR_INSTANCE, IdentityProviderAccountAlreadyLinkedError, isIdentityProviderAccountAlreadyLinkedError } from "./identity/provider/account/error.mjs";
140
141
  import { IdentityProviderMapperOperation } from "./identity/provider/mapper/constants.mjs";
141
142
  import { IdentityProviderAccountBaseMapper } from "./identity/provider/mapper/base.mjs";
@@ -187,4 +188,4 @@ import { UserProvisioningSynchronizer } from "./provisioning/synchronizer/user/m
187
188
  import { WildcardRealmProvisioner, expandWildcardRealmEntry, extractWildcardRealmEntry } from "./provisioning/wildcard/module.mjs";
188
189
  import "./provisioning/index.mjs";
189
190
  import "./security/index.mjs";
190
- export { BaseCredentialsAuthenticator, CLIENT_READ_PERMISSIONS, CONSENT_FILTER_KEYS, CONSENT_SCOPE_MAX_LENGTH, ClientAuthenticator, ClientCertificateValidator, ClientCredentialsGrant, ClientCredentialsService, ClientPermissionService, ClientProvisioningSynchronizer, ClientProvisioningValidator, ClientRoleService, ClientScopeService, ClientService, ConsentService, CredentialsAuthenticator, EVENT_ACTOR_NAME_MAX_LENGTH, EVENT_DIFF_SECRET_KEY_REGEX, EVENT_DIFF_VALUE_MAX_LENGTH, EVENT_LOG_RETENTION_DAYS_DEFAULT, EntityEventHandler, EventService, GraphProvisioningSynchronizer, IDENTITY_PROVIDER_ACCOUNT_ALREADY_LINKED_ERROR_INSTANCE, IDENTITY_PROVIDER_ACCOUNT_FILTER_KEYS, IDENTITY_PROVIDER_ACCOUNT_UNLINK_BLOCKED_ERROR_INSTANCE, IDENTITY_PROVIDER_LDAP_COLLECTION_AUTHENTICATOR_TOKEN, IdentityGrantType, IdentityPermissionProvider, IdentityProviderAccountAlreadyLinkedError, IdentityProviderAccountBaseMapper, IdentityProviderAccountManager, IdentityProviderAccountService, IdentityProviderAccountUnlinkBlockedError, IdentityProviderAttributeMapper, IdentityProviderFacebookAuthenticator, IdentityProviderGithubAuthenticator, IdentityProviderGoogleAuthenticator, IdentityProviderInstagramAuthenticator, IdentityProviderLdapAuthenticator, IdentityProviderLdapCollectionAuthenticator, IdentityProviderMapperOperation, IdentityProviderOAuth2Authenticator, IdentityProviderOpenIDAuthenticator, IdentityProviderPaypalAuthenticator, IdentityProviderPermissionMapper, IdentityProviderRoleMapper, IdentityProviderRoleMappingService, IdentityResolver, IdentityRoleProvider, KEY_CERTIFICATE_ERROR_INSTANCE, KeyCertificateError, KeyProvisioner, KeyService, LoginThrottleService, MAIL_TEMPLATE_REGISTRY, MailTemplateName, MailTemplateRenderer, NoopAuthFlowMetrics, OAuth2AccessPolicyEvaluator, OAuth2AccessTokenIssuer, OAuth2Authorization, OAuth2AuthorizationCodeIssuer, OAuth2AuthorizationCodeRequestValidator, OAuth2AuthorizationCodeRequestVerifier, OAuth2AuthorizationCodeVerifier, OAuth2AuthorizationStateManager, OAuth2AuthorizeGrant, OAuth2ClientAuthenticator, OAuth2EndSessionRequestValidator, OAuth2EndSessionService, OAuth2MfaLoginService, OAuth2MfaTokenIssuer, OAuth2OpenIDClaimsBuilder, OAuth2OpenIDTokenIssuer, OAuth2RefreshTokenGrant, OAuth2RefreshTokenIssuer, OAuth2ScopeAttributesResolver, OAuth2TokenRevoker, OAuth2TokenSigner, OAuth2TokenVerifier, PASSWORD_RESET_EXPIRES_IN_MINUTES, PasswordGrantType, PasswordRecoveryService, PermissionBindingPolicyEvaluator, PermissionCheckerService, PermissionPolicyService, PermissionProvisioningRelationsValidator, PermissionProvisioningSynchronizer, PermissionProvisioningValidator, PermissionService, PolicyCheckerService, PolicyEngine, PolicyProvisioningSynchronizer, PolicyProvisioningValidator, PolicyService, ProvisioningEntityResolver, ProvisioningEntityStrategyType, ProvisioningJunctionSynchronizer, ProvisioningStrategyValidator, REALM_CIPHER_BLOB_ERROR_INSTANCE, REALM_CIPHER_BLOB_VERSION, REALM_WILDCARD_NAME, RECORD_QUERY_PARAMETERS, RealmCipher, RealmCipherBlobError, RealmProvisioningSynchronizer, RealmProvisioningValidator, RealmService, RealmWildcardProvisioningValidator, RegistrationService, RoleAttributeService, RolePermissionService, RoleProvisioningSynchronizer, RoleProvisioningValidator, RoleService, RootProvisioningValidator, SESSION_FILTER_KEYS, SESSION_TOKEN_FILTER_KEYS, SESSION_TOKEN_RELATION_MISSING_ERROR_INSTANCE, SYSTEM_CLIENT_DEFINITIONS, SYSTEM_CLIENT_SCOPE_NAMES, ScopeProvisioningSynchronizer, ScopeProvisioningValidator, ScopeService, SessionManager, SessionService, SessionTokenRelationMissingError, SessionTokenService, SystemClientProvisioner, TrustAnchorService, USER_AUTHENTICATOR_ATTEMPT_CACHE_PREFIX, USER_AUTHENTICATOR_ATTEMPT_LOCK_FACTOR, USER_AUTHENTICATOR_ATTEMPT_LOCK_MAX, USER_AUTHENTICATOR_ATTEMPT_WINDOW, USER_AUTHENTICATOR_EMAIL_CODE_CACHE_PREFIX, USER_AUTHENTICATOR_EMAIL_CODE_EXPIRES_IN_MINUTES, USER_AUTHENTICATOR_EMAIL_CODE_LENGTH, USER_AUTHENTICATOR_EMAIL_SEND_CACHE_PREFIX, USER_AUTHENTICATOR_EMAIL_SEND_COOLDOWN, USER_AUTHENTICATOR_FILTER_KEYS, USER_AUTHENTICATOR_RECOVERY_CODE_COUNT, USER_AUTHENTICATOR_THROTTLE_CACHE_PREFIX, USER_AUTHENTICATOR_TOTP_ALGORITHM, USER_AUTHENTICATOR_TOTP_DIGITS, USER_AUTHENTICATOR_TOTP_PERIOD, USER_AUTHENTICATOR_VERIFY_LOCK_CACHE_PREFIX, USER_AUTHENTICATOR_VERIFY_LOCK_RENEW_INTERVAL, USER_AUTHENTICATOR_VERIFY_LOCK_TTL, USER_AUTHENTICATOR_WEBAUTHN_AUTH_CACHE_PREFIX, USER_AUTHENTICATOR_WEBAUTHN_CHALLENGE_WINDOW, USER_AUTHENTICATOR_WEBAUTHN_REG_CACHE_PREFIX, UserAttributeService, UserAuthenticator, UserAuthenticatorService, UserCredentialsService, UserPermissionService, UserProvisioningSynchronizer, UserProvisioningValidator, UserRoleService, UserService, WRAPPED_KEY_MATERIAL_PREFIX, WildcardRealmProvisioner, appendQueryConditions, applyJunctionCreateGrant, assertCertificateMatchesKey, assertClientCertificateEvidenceValidForBinding, assertClientGrantAllowed, base64URLEncode, buildCertificateJwkFields, buildClientCertificateThumbprint, buildEntityDiff, buildJunctionUpdateData, buildOAuth2BearerTokenResponse, buildOAuth2CodeChallenge, buildOAuth2TokenHash, buildProvisioningEntityKey, buildSystemClientAttributes, buildWebauthnAuthenticationOptions, buildWebauthnRegistrationOptions, buildX5c, buildX5tS256, clientPermissionSchema, clientRoleSchema, clientSchema, clientScopeSchema, consentSchema, createIdentityProviderOAuth2Authenticator, createProvisioningEntitiesValidator, createRelationsReadGate, decodeQuery, defineMailTemplate, deriveAmrAcr, describeQuerySchema, eventSchema, expandWildcardRealmEntry, extractWildcardRealmEntry, generateNumericCode, generateOAuth2CodeVerifier, generateRecoveryCode, guessUserAuthenticatorKindByResponse, identityProviderAccountSchema, identityProviderRoleMappingSchema, identityProviderSchema, isIdentityProviderAccountAlreadyLinkedError, isIdentityProviderAccountUnlinkBlockedError, isRealmCipherBlobError, isSessionTokenRelationMissingError, isWrappedKeyMaterial, keySchema, mergeProvisioningEntities, mergeProvisioningEntity, normalizeEntityProvisioningStrategy, parseCertificateChain, parseClientCertificateChain, permissionPolicySchema, permissionSchema, policySchema, queryCodec, realmSchema, roleAttributeSchema, rolePermissionSchema, roleSchema, sanitizeEventData, schemaRegistry, schemas, scopeSchema, sessionSchema, sessionTokenSchema, toIdentityPolicyData, trustAnchorSchema, unwrapKeyMaterial, userAttributeSchema, userAuthenticatorSchema, userPermissionSchema, userRoleSchema, userSchema, verifyWebauthnAuthentication, verifyWebauthnRegistration, wrapKeyMaterial };
191
+ export { BaseCredentialsAuthenticator, CLIENT_READ_PERMISSIONS, CONSENT_FILTER_KEYS, CONSENT_SCOPE_MAX_LENGTH, ClientAuthenticator, ClientCertificateValidator, ClientCredentialsGrant, ClientCredentialsService, ClientPermissionService, ClientProvisioningSynchronizer, ClientProvisioningValidator, ClientRoleService, ClientScopeService, ClientService, ConsentService, CredentialsAuthenticator, EVENT_ACTOR_NAME_MAX_LENGTH, EVENT_DIFF_SECRET_KEY_REGEX, EVENT_DIFF_VALUE_MAX_LENGTH, EVENT_LOG_RETENTION_DAYS_DEFAULT, EntityEventHandler, EventService, GraphProvisioningSynchronizer, IDENTITY_PROVIDER_ACCOUNT_ALREADY_LINKED_ERROR_INSTANCE, IDENTITY_PROVIDER_ACCOUNT_FILTER_KEYS, IDENTITY_PROVIDER_ACCOUNT_LINK_TTL, IDENTITY_PROVIDER_ACCOUNT_UNLINK_BLOCKED_ERROR_INSTANCE, IDENTITY_PROVIDER_LDAP_COLLECTION_AUTHENTICATOR_TOKEN, IdentityGrantType, IdentityPermissionProvider, IdentityProviderAccountAlreadyLinkedError, IdentityProviderAccountBaseMapper, IdentityProviderAccountManager, IdentityProviderAccountService, IdentityProviderAccountUnlinkBlockedError, IdentityProviderAttributeMapper, IdentityProviderFacebookAuthenticator, IdentityProviderGithubAuthenticator, IdentityProviderGoogleAuthenticator, IdentityProviderInstagramAuthenticator, IdentityProviderLdapAuthenticator, IdentityProviderLdapCollectionAuthenticator, IdentityProviderMapperOperation, IdentityProviderOAuth2Authenticator, IdentityProviderOpenIDAuthenticator, IdentityProviderPaypalAuthenticator, IdentityProviderPermissionMapper, IdentityProviderRoleMapper, IdentityProviderRoleMappingService, IdentityResolver, IdentityRoleProvider, KEY_CERTIFICATE_ERROR_INSTANCE, KeyCertificateError, KeyProvisioner, KeyService, LoginThrottleService, MAIL_TEMPLATE_REGISTRY, MailTemplateName, MailTemplateRenderer, NoopAuthFlowMetrics, OAuth2AccessPolicyEvaluator, OAuth2AccessTokenIssuer, OAuth2Authorization, OAuth2AuthorizationCodeIssuer, OAuth2AuthorizationCodeRequestValidator, OAuth2AuthorizationCodeRequestVerifier, OAuth2AuthorizationCodeVerifier, OAuth2AuthorizationStateManager, OAuth2AuthorizeGrant, OAuth2ClientAuthenticator, OAuth2EndSessionRequestValidator, OAuth2EndSessionService, OAuth2MfaLoginService, OAuth2MfaTokenIssuer, OAuth2OpenIDClaimsBuilder, OAuth2OpenIDTokenIssuer, OAuth2RefreshTokenGrant, OAuth2RefreshTokenIssuer, OAuth2ScopeAttributesResolver, OAuth2TokenRevoker, OAuth2TokenSigner, OAuth2TokenVerifier, PASSWORD_RESET_EXPIRES_IN_MINUTES, PasswordGrantType, PasswordRecoveryService, PermissionBindingPolicyEvaluator, PermissionCheckerService, PermissionPolicyService, PermissionProvisioningRelationsValidator, PermissionProvisioningSynchronizer, PermissionProvisioningValidator, PermissionService, PolicyCheckerService, PolicyEngine, PolicyProvisioningSynchronizer, PolicyProvisioningValidator, PolicyService, ProvisioningEntityResolver, ProvisioningEntityStrategyType, ProvisioningJunctionSynchronizer, ProvisioningStrategyValidator, REALM_CIPHER_BLOB_ERROR_INSTANCE, REALM_CIPHER_BLOB_VERSION, REALM_WILDCARD_NAME, RECORD_QUERY_PARAMETERS, RealmCipher, RealmCipherBlobError, RealmProvisioningSynchronizer, RealmProvisioningValidator, RealmService, RealmWildcardProvisioningValidator, RegistrationService, RoleAttributeService, RolePermissionService, RoleProvisioningSynchronizer, RoleProvisioningValidator, RoleService, RootProvisioningValidator, SESSION_FILTER_KEYS, SESSION_TOKEN_FILTER_KEYS, SESSION_TOKEN_RELATION_MISSING_ERROR_INSTANCE, SYSTEM_CLIENT_DEFINITIONS, SYSTEM_CLIENT_SCOPE_NAMES, ScopeProvisioningSynchronizer, ScopeProvisioningValidator, ScopeService, SessionManager, SessionService, SessionTokenRelationMissingError, SessionTokenService, SystemClientProvisioner, TrustAnchorService, USER_AUTHENTICATOR_ATTEMPT_CACHE_PREFIX, USER_AUTHENTICATOR_ATTEMPT_LOCK_FACTOR, USER_AUTHENTICATOR_ATTEMPT_LOCK_MAX, USER_AUTHENTICATOR_ATTEMPT_WINDOW, USER_AUTHENTICATOR_EMAIL_CODE_CACHE_PREFIX, USER_AUTHENTICATOR_EMAIL_CODE_EXPIRES_IN_MINUTES, USER_AUTHENTICATOR_EMAIL_CODE_LENGTH, USER_AUTHENTICATOR_EMAIL_SEND_CACHE_PREFIX, USER_AUTHENTICATOR_EMAIL_SEND_COOLDOWN, USER_AUTHENTICATOR_FILTER_KEYS, USER_AUTHENTICATOR_RECOVERY_CODE_COUNT, USER_AUTHENTICATOR_THROTTLE_CACHE_PREFIX, USER_AUTHENTICATOR_TOTP_ALGORITHM, USER_AUTHENTICATOR_TOTP_DIGITS, USER_AUTHENTICATOR_TOTP_PERIOD, USER_AUTHENTICATOR_VERIFY_LOCK_CACHE_PREFIX, USER_AUTHENTICATOR_VERIFY_LOCK_RENEW_INTERVAL, USER_AUTHENTICATOR_VERIFY_LOCK_TTL, USER_AUTHENTICATOR_WEBAUTHN_AUTH_CACHE_PREFIX, USER_AUTHENTICATOR_WEBAUTHN_CHALLENGE_WINDOW, USER_AUTHENTICATOR_WEBAUTHN_REG_CACHE_PREFIX, UserAttributeService, UserAuthenticator, UserAuthenticatorService, UserCredentialsService, UserPermissionService, UserProvisioningSynchronizer, UserProvisioningValidator, UserRoleService, UserService, WRAPPED_KEY_MATERIAL_PREFIX, WildcardRealmProvisioner, appendQueryConditions, applyJunctionCreateGrant, assertCertificateMatchesKey, assertClientCertificateEvidenceValidForBinding, assertClientGrantAllowed, base64URLEncode, buildCertificateJwkFields, buildClientCertificateThumbprint, buildEntityDiff, buildJunctionUpdateData, buildOAuth2BearerTokenResponse, buildOAuth2CodeChallenge, buildOAuth2TokenHash, buildProvisioningEntityKey, buildSystemClientAttributes, buildWebauthnAuthenticationOptions, buildWebauthnRegistrationOptions, buildX5c, buildX5tS256, clientPermissionSchema, clientRoleSchema, clientSchema, clientScopeSchema, consentSchema, createIdentityProviderOAuth2Authenticator, createProvisioningEntitiesValidator, createRelationsReadGate, decodeQuery, defineMailTemplate, deriveAmrAcr, describeQuerySchema, eventSchema, expandWildcardRealmEntry, extractWildcardRealmEntry, generateNumericCode, generateOAuth2CodeVerifier, generateRecoveryCode, guessUserAuthenticatorKindByResponse, identityProviderAccountSchema, identityProviderRoleMappingSchema, identityProviderSchema, isIdentityProviderAccountAlreadyLinkedError, isIdentityProviderAccountUnlinkBlockedError, isRealmCipherBlobError, isSessionTokenRelationMissingError, isWrappedKeyMaterial, keySchema, mergeProvisioningEntities, mergeProvisioningEntity, normalizeEntityProvisioningStrategy, parseCertificateChain, parseClientCertificateChain, permissionPolicySchema, permissionSchema, policySchema, queryCodec, realmSchema, roleAttributeSchema, rolePermissionSchema, roleSchema, sanitizeEventData, schemaRegistry, schemas, scopeSchema, sessionSchema, sessionTokenSchema, toIdentityPolicyData, trustAnchorSchema, unwrapKeyMaterial, userAttributeSchema, userAuthenticatorSchema, userPermissionSchema, userRoleSchema, userSchema, verifyWebauthnAuthentication, verifyWebauthnRegistration, wrapKeyMaterial };
@@ -1 +1 @@
1
- {"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../../../../../../src/core/oauth2/authorization/code-request/verifier/module.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,8BAA8B,EAAE,MAAM,kBAAkB,CAAC;AAWvE,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AAExE,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AACtE,OAAO,KAAK,EACR,uCAAuC,EACvC,gDAAgD,EAChD,6CAA6C,EAChD,MAAM,YAAY,CAAC;AAEpB,qBAAa,sCAAuC,YAAW,uCAAuC;IAClG,SAAS,CAAC,gBAAgB,EAAE,uBAAuB,CAAC;IAEpD,SAAS,CAAC,eAAe,EAAE,sBAAsB,CAAC;gBAEtC,GAAG,EAAE,6CAA6C;IAK9D;;;OAGG;IACG,MAAM,CACR,IAAI,EAAE,8BAA8B,GACpC,OAAO,CAAC,gDAAgD,CAAC;CA6FhE"}
1
+ {"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../../../../../../src/core/oauth2/authorization/code-request/verifier/module.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,8BAA8B,EAAE,MAAM,kBAAkB,CAAC;AAWvE,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AAExE,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AACtE,OAAO,KAAK,EACR,uCAAuC,EACvC,gDAAgD,EAChD,6CAA6C,EAChD,MAAM,YAAY,CAAC;AAEpB,qBAAa,sCAAuC,YAAW,uCAAuC;IAClG,SAAS,CAAC,gBAAgB,EAAE,uBAAuB,CAAC;IAEpD,SAAS,CAAC,eAAe,EAAE,sBAAsB,CAAC;gBAEtC,GAAG,EAAE,6CAA6C;IAK9D;;;OAGG;IACG,MAAM,CACR,IAAI,EAAE,8BAA8B,GACpC,OAAO,CAAC,gDAAgD,CAAC;CAmGhE"}
@@ -34,10 +34,11 @@ var OAuth2AuthorizationCodeRequestVerifier = class {
34
34
  if (data.scope) {
35
35
  if (!hasOAuth2Scopes(scopeNames, data.scope) && !hasOAuth2Scopes(data.scope, ScopeName.GLOBAL)) throw OAuth2ScopeError.insufficient();
36
36
  } else data.scope = scopeNames.join(" ");
37
- const redirectUriVerified = !!data.redirect_uri;
37
+ let redirectUriVerified = false;
38
38
  if (data.redirect_uri) {
39
39
  const redirectUris = client.redirectUri.split(",");
40
40
  if (!isSimpleURLMatch(data.redirect_uri, redirectUris)) throw OAuth2GrantError.redirectUriMismatch();
41
+ redirectUriVerified = true;
41
42
  }
42
43
  return {
43
44
  data,
@@ -1 +1 @@
1
- {"version":3,"file":"module.mjs","names":["ScopeName","isClientPublic","isSimpleURLMatch","isUUID","OAuth2ClientError","OAuth2GrantError","OAuth2RequestError","OAuth2ScopeError","OAuth2TokenGrant","hasOAuth2Scopes","assertClientGrantAllowed","OAuth2AuthorizationCodeRequestVerifier","clientRepository","scopeRepository","ctx","verify","data","client_id","invalid","realm_id","malformed","client","findOneByIdOrName","active","inactive","AUTHORIZATION_CODE","redirectUri","redirectUriMismatch","code_challenge","state","id","realmId","scopes","findByClientId","scopeNames","map","scope","name","GLOBAL","insufficient","join","redirectUriVerified","redirect_uri","redirectUris","split"],"sources":["../../../../../../src/core/oauth2/authorization/code-request/verifier/module.ts"],"sourcesContent":["/*\n * Copyright (c) 2025.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport type { OAuth2AuthorizationCodeRequest } from '@authup/core-kit';\nimport { ScopeName, isClientPublic } from '@authup/core-kit';\nimport { isSimpleURLMatch, isUUID } from '@authup/kit';\nimport {\n OAuth2ClientError,\n OAuth2GrantError,\n OAuth2RequestError,\n OAuth2ScopeError,\n OAuth2TokenGrant,\n hasOAuth2Scopes,\n} from '@authup/specs';\nimport type { IOAuth2ClientRepository } from '../../../client/index.ts';\nimport { assertClientGrantAllowed } from '../../../client/index.ts';\nimport type { IOAuth2ScopeRepository } from '../../../scope/index.ts';\nimport type {\n IOAuth2AuthorizationCodeRequestVerifier,\n OAuth2AuthorizationCodeRequestVerificationResult,\n OAuth2AuthorizationCodeRequestVerifierContext,\n} from './types.ts';\n\nexport class OAuth2AuthorizationCodeRequestVerifier implements IOAuth2AuthorizationCodeRequestVerifier {\n protected clientRepository: IOAuth2ClientRepository;\n\n protected scopeRepository: IOAuth2ScopeRepository;\n\n constructor(ctx: OAuth2AuthorizationCodeRequestVerifierContext) {\n this.clientRepository = ctx.clientRepository;\n this.scopeRepository = ctx.scopeRepository;\n }\n\n /**\n * Verify validated authorization code request.\n * @param data\n */\n async verify(\n data: OAuth2AuthorizationCodeRequest,\n ) : Promise<OAuth2AuthorizationCodeRequestVerificationResult> {\n if (!data.client_id) {\n throw OAuth2ClientError.invalid();\n }\n\n // A name-identified client needs a realm hint to resolve deterministically\n // — client names are only unique per realm (every realm carries the\n // same-named system clients, and a wildcard-provisioned client exists in\n // every realm), so a bare name would bind to an arbitrary realm's client\n // (and, post realm-gate, produce a confusing mismatch against a random\n // realm). Require the hint.\n if (!isUUID(data.client_id) && !data.realm_id) {\n throw OAuth2RequestError.malformed('A realm is required to resolve a client by name.');\n }\n\n const client = await this.clientRepository.findOneByIdOrName(data.client_id, data.realm_id);\n if (!client) {\n throw OAuth2ClientError.invalid();\n }\n\n if (!client.active) {\n throw OAuth2ClientError.inactive();\n }\n\n // A non-null grant_types allowlist must cover the code flow — an RP\n // misconfiguration fails at the front door, not at code redemption.\n assertClientGrantAllowed(client, OAuth2TokenGrant.AUTHORIZATION_CODE);\n\n // OAuth 2.1 posture: a client with no registered redirect_uri pattern\n // can never be matched — reject outright instead of trusting whatever\n // redirect_uri the request carries (the server would otherwise issue a\n // code to an attacker-supplied URI).\n if (!client.redirectUri) {\n throw OAuth2GrantError.redirectUriMismatch();\n }\n\n // Public clients MUST use PKCE (RFC 7636 §4.4.1, OAuth 2.1). Without\n // PKCE a public client's code flow has no second factor — anyone who\n // intercepts the redirect can redeem the code at /token. The code flow\n // is the only supported response type, so this holds unconditionally.\n if (isClientPublic(client) && !data.code_challenge) {\n throw OAuth2RequestError.malformed('PKCE code_challenge is required for public clients.');\n }\n\n // Public clients SHOULD include state to bind the redirect to the\n // initiating session and prevent CSRF (RFC 6749 §10.12). Confidential\n // clients are exempt because the /token exchange already authenticates\n // them via client_secret.\n if (isClientPublic(client) && !data.state) {\n throw OAuth2RequestError.malformed('state is required for public clients in the code flow.');\n }\n\n data.client_id = client.id;\n data.realm_id = client.realmId;\n\n const scopes = await this.scopeRepository.findByClientId(client.id);\n const scopeNames = scopes.map((scope) => scope.name);\n if (data.scope) {\n if (\n !hasOAuth2Scopes(scopeNames, data.scope) &&\n !hasOAuth2Scopes(data.scope, ScopeName.GLOBAL)\n ) {\n throw OAuth2ScopeError.insufficient();\n }\n } else {\n data.scope = scopeNames.join(' ');\n }\n\n // Verified only when the request's redirect_uri matched a registered\n // pattern (pattern-less clients were rejected above). A request without\n // a redirect_uri (e.g. the GET page render) stays unverified so\n // consumers never auto-redirect without a match.\n const redirectUriVerified = !!data.redirect_uri;\n if (data.redirect_uri) {\n const redirectUris = client.redirectUri.split(',');\n\n // isSimpleURLMatch, never isSimpleMatch: the raw matcher treats `/`\n // as its only boundary, so a `*` in a registered pattern's host\n // absorbs a `?`, `#` or `\\` and the pattern's remaining host\n // literal lands in the query of a foreign origin. The code would\n // then be issued to that origin.\n if (!isSimpleURLMatch(data.redirect_uri, redirectUris)) {\n throw OAuth2GrantError.redirectUriMismatch();\n }\n }\n\n return {\n data,\n client,\n scopes,\n redirectUriVerified,\n };\n }\n}\n"],"mappings":";;;;;;;;;AA2BA,IAAaW,yCAAb,MAAaA;CACCC;CAEAC;CAEV,YAAYC,KAAoD;EAC5D,KAAKF,mBAAmBE,IAAIF;EAC5B,KAAKC,kBAAkBC,IAAID;CAC/B;;;;IAMA,MAAME,OACFC,MAC0D;EAC1D,IAAI,CAACA,KAAKC,WACN,MAAMb,kBAAkBc,QAAO;EASnC,IAAI,CAACf,OAAOa,KAAKC,SAAS,KAAK,CAACD,KAAKG,UACjC,MAAMb,mBAAmBc,UAAU,kDAAA;EAGvC,MAAMC,SAAS,MAAM,KAAKT,iBAAiBU,kBAAkBN,KAAKC,WAAWD,KAAKG,QAAQ;EAC1F,IAAI,CAACE,QACD,MAAMjB,kBAAkBc,QAAO;EAGnC,IAAI,CAACG,OAAOE,QACR,MAAMnB,kBAAkBoB,SAAQ;EAKpCd,yBAAyBW,QAAQb,iBAAiBiB,kBAAkB;EAMpE,IAAI,CAACJ,OAAOK,aACR,MAAMrB,iBAAiBsB,oBAAmB;EAO9C,IAAI1B,eAAeoB,MAAAA,KAAW,CAACL,KAAKY,gBAChC,MAAMtB,mBAAmBc,UAAU,qDAAA;EAOvC,IAAInB,eAAeoB,MAAAA,KAAW,CAACL,KAAKa,OAChC,MAAMvB,mBAAmBc,UAAU,wDAAA;EAGvCJ,KAAKC,YAAYI,OAAOS;EACxBd,KAAKG,WAAWE,OAAOU;EAEvB,MAAMC,SAAS,MAAM,KAAKnB,gBAAgBoB,eAAeZ,OAAOS,EAAE;EAClE,MAAMI,aAAaF,OAAOG,KAAKC,UAAUA,MAAMC,IAAI;EACnD,IAAIrB,KAAKoB,OAED;OAAA,CAAC3B,gBAAgByB,YAAYlB,KAAKoB,KAAK,KACvC,CAAC3B,gBAAgBO,KAAKoB,OAAOpC,UAAUsC,MAAM,GAE7C,MAAM/B,iBAAiBgC,aAAY;EAAA,OAGvCvB,KAAKoB,QAAQF,WAAWM,KAAK,GAAA;EAOjC,MAAMC,sBAAsB,CAAC,CAACzB,KAAK0B;EACnC,IAAI1B,KAAK0B,cAAc;GACnB,MAAMC,eAAetB,OAAOK,YAAYkB,MAAM,GAAA;GAO9C,IAAI,CAAC1C,iBAAiBc,KAAK0B,cAAcC,YAAAA,GACrC,MAAMtC,iBAAiBsB,oBAAmB;EAElD;EAEA,OAAO;GACHX;GACAK;GACAW;GACAS;EACJ;CACJ;AACJ"}
1
+ {"version":3,"file":"module.mjs","names":["ScopeName","isClientPublic","isSimpleURLMatch","isUUID","OAuth2ClientError","OAuth2GrantError","OAuth2RequestError","OAuth2ScopeError","OAuth2TokenGrant","hasOAuth2Scopes","assertClientGrantAllowed","OAuth2AuthorizationCodeRequestVerifier","clientRepository","scopeRepository","ctx","verify","data","client_id","invalid","realm_id","malformed","client","findOneByIdOrName","active","inactive","AUTHORIZATION_CODE","redirectUri","redirectUriMismatch","code_challenge","state","id","realmId","scopes","findByClientId","scopeNames","map","scope","name","GLOBAL","insufficient","join","redirectUriVerified","redirect_uri","redirectUris","split"],"sources":["../../../../../../src/core/oauth2/authorization/code-request/verifier/module.ts"],"sourcesContent":["/*\n * Copyright (c) 2025.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport type { OAuth2AuthorizationCodeRequest } from '@authup/core-kit';\nimport { ScopeName, isClientPublic } from '@authup/core-kit';\nimport { isSimpleURLMatch, isUUID } from '@authup/kit';\nimport {\n OAuth2ClientError,\n OAuth2GrantError,\n OAuth2RequestError,\n OAuth2ScopeError,\n OAuth2TokenGrant,\n hasOAuth2Scopes,\n} from '@authup/specs';\nimport type { IOAuth2ClientRepository } from '../../../client/index.ts';\nimport { assertClientGrantAllowed } from '../../../client/index.ts';\nimport type { IOAuth2ScopeRepository } from '../../../scope/index.ts';\nimport type {\n IOAuth2AuthorizationCodeRequestVerifier,\n OAuth2AuthorizationCodeRequestVerificationResult,\n OAuth2AuthorizationCodeRequestVerifierContext,\n} from './types.ts';\n\nexport class OAuth2AuthorizationCodeRequestVerifier implements IOAuth2AuthorizationCodeRequestVerifier {\n protected clientRepository: IOAuth2ClientRepository;\n\n protected scopeRepository: IOAuth2ScopeRepository;\n\n constructor(ctx: OAuth2AuthorizationCodeRequestVerifierContext) {\n this.clientRepository = ctx.clientRepository;\n this.scopeRepository = ctx.scopeRepository;\n }\n\n /**\n * Verify validated authorization code request.\n * @param data\n */\n async verify(\n data: OAuth2AuthorizationCodeRequest,\n ) : Promise<OAuth2AuthorizationCodeRequestVerificationResult> {\n if (!data.client_id) {\n throw OAuth2ClientError.invalid();\n }\n\n // A name-identified client needs a realm hint to resolve deterministically\n // — client names are only unique per realm (every realm carries the\n // same-named system clients, and a wildcard-provisioned client exists in\n // every realm), so a bare name would bind to an arbitrary realm's client\n // (and, post realm-gate, produce a confusing mismatch against a random\n // realm). Require the hint.\n if (!isUUID(data.client_id) && !data.realm_id) {\n throw OAuth2RequestError.malformed('A realm is required to resolve a client by name.');\n }\n\n const client = await this.clientRepository.findOneByIdOrName(data.client_id, data.realm_id);\n if (!client) {\n throw OAuth2ClientError.invalid();\n }\n\n if (!client.active) {\n throw OAuth2ClientError.inactive();\n }\n\n // A non-null grant_types allowlist must cover the code flow — an RP\n // misconfiguration fails at the front door, not at code redemption.\n assertClientGrantAllowed(client, OAuth2TokenGrant.AUTHORIZATION_CODE);\n\n // OAuth 2.1 posture: a client with no registered redirect_uri pattern\n // can never be matched — reject outright instead of trusting whatever\n // redirect_uri the request carries (the server would otherwise issue a\n // code to an attacker-supplied URI).\n if (!client.redirectUri) {\n throw OAuth2GrantError.redirectUriMismatch();\n }\n\n // Public clients MUST use PKCE (RFC 7636 §4.4.1, OAuth 2.1). Without\n // PKCE a public client's code flow has no second factor — anyone who\n // intercepts the redirect can redeem the code at /token. The code flow\n // is the only supported response type, so this holds unconditionally.\n if (isClientPublic(client) && !data.code_challenge) {\n throw OAuth2RequestError.malformed('PKCE code_challenge is required for public clients.');\n }\n\n // Public clients SHOULD include state to bind the redirect to the\n // initiating session and prevent CSRF (RFC 6749 §10.12). Confidential\n // clients are exempt because the /token exchange already authenticates\n // them via client_secret.\n if (isClientPublic(client) && !data.state) {\n throw OAuth2RequestError.malformed('state is required for public clients in the code flow.');\n }\n\n data.client_id = client.id;\n data.realm_id = client.realmId;\n\n const scopes = await this.scopeRepository.findByClientId(client.id);\n const scopeNames = scopes.map((scope) => scope.name);\n if (data.scope) {\n if (\n !hasOAuth2Scopes(scopeNames, data.scope) &&\n !hasOAuth2Scopes(data.scope, ScopeName.GLOBAL)\n ) {\n throw OAuth2ScopeError.insufficient();\n }\n } else {\n data.scope = scopeNames.join(' ');\n }\n\n // Verified only when the request's redirect_uri matched a registered\n // pattern (pattern-less clients were rejected above). A request without\n // a redirect_uri (e.g. the GET page render) stays unverified so\n // consumers never auto-redirect without a match.\n //\n // Set from the match itself, never from mere presence: consumers make\n // redirect decisions on this flag, so it must not survive a refactor\n // that turns the throw below into a soft branch.\n let redirectUriVerified = false;\n if (data.redirect_uri) {\n const redirectUris = client.redirectUri.split(',');\n\n // isSimpleURLMatch, never isSimpleMatch: the raw matcher treats `/`\n // as its only boundary, so a `*` in a registered pattern's host\n // absorbs a `?`, `#` or `\\` and the pattern's remaining host\n // literal lands in the query of a foreign origin. The code would\n // then be issued to that origin.\n if (!isSimpleURLMatch(data.redirect_uri, redirectUris)) {\n throw OAuth2GrantError.redirectUriMismatch();\n }\n\n redirectUriVerified = true;\n }\n\n return {\n data,\n client,\n scopes,\n redirectUriVerified,\n };\n }\n}\n"],"mappings":";;;;;;;;;AA2BA,IAAaW,yCAAb,MAAaA;CACCC;CAEAC;CAEV,YAAYC,KAAoD;EAC5D,KAAKF,mBAAmBE,IAAIF;EAC5B,KAAKC,kBAAkBC,IAAID;CAC/B;;;;IAMA,MAAME,OACFC,MAC0D;EAC1D,IAAI,CAACA,KAAKC,WACN,MAAMb,kBAAkBc,QAAO;EASnC,IAAI,CAACf,OAAOa,KAAKC,SAAS,KAAK,CAACD,KAAKG,UACjC,MAAMb,mBAAmBc,UAAU,kDAAA;EAGvC,MAAMC,SAAS,MAAM,KAAKT,iBAAiBU,kBAAkBN,KAAKC,WAAWD,KAAKG,QAAQ;EAC1F,IAAI,CAACE,QACD,MAAMjB,kBAAkBc,QAAO;EAGnC,IAAI,CAACG,OAAOE,QACR,MAAMnB,kBAAkBoB,SAAQ;EAKpCd,yBAAyBW,QAAQb,iBAAiBiB,kBAAkB;EAMpE,IAAI,CAACJ,OAAOK,aACR,MAAMrB,iBAAiBsB,oBAAmB;EAO9C,IAAI1B,eAAeoB,MAAAA,KAAW,CAACL,KAAKY,gBAChC,MAAMtB,mBAAmBc,UAAU,qDAAA;EAOvC,IAAInB,eAAeoB,MAAAA,KAAW,CAACL,KAAKa,OAChC,MAAMvB,mBAAmBc,UAAU,wDAAA;EAGvCJ,KAAKC,YAAYI,OAAOS;EACxBd,KAAKG,WAAWE,OAAOU;EAEvB,MAAMC,SAAS,MAAM,KAAKnB,gBAAgBoB,eAAeZ,OAAOS,EAAE;EAClE,MAAMI,aAAaF,OAAOG,KAAKC,UAAUA,MAAMC,IAAI;EACnD,IAAIrB,KAAKoB,OAED;OAAA,CAAC3B,gBAAgByB,YAAYlB,KAAKoB,KAAK,KACvC,CAAC3B,gBAAgBO,KAAKoB,OAAOpC,UAAUsC,MAAM,GAE7C,MAAM/B,iBAAiBgC,aAAY;EAAA,OAGvCvB,KAAKoB,QAAQF,WAAWM,KAAK,GAAA;EAWjC,IAAIC,sBAAsB;EAC1B,IAAIzB,KAAK0B,cAAc;GACnB,MAAMC,eAAetB,OAAOK,YAAYkB,MAAM,GAAA;GAO9C,IAAI,CAAC1C,iBAAiBc,KAAK0B,cAAcC,YAAAA,GACrC,MAAMtC,iBAAiBsB,oBAAmB;GAG9Cc,sBAAsB;EAC1B;EAEA,OAAO;GACHzB;GACAK;GACAW;GACAS;EACJ;CACJ;AACJ"}