@authup/server-core 1.0.0-beta.59 → 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.
- package/dist/adapters/database/domains/client/entity.d.ts.map +1 -1
- package/dist/adapters/database/domains/client/entity.mjs +58 -30
- package/dist/adapters/database/domains/client/entity.mjs.map +1 -1
- package/dist/adapters/database/domains/client-permission/entity.d.ts.map +1 -1
- package/dist/adapters/database/domains/client-permission/entity.mjs +48 -24
- package/dist/adapters/database/domains/client-permission/entity.mjs.map +1 -1
- package/dist/adapters/database/domains/client-role/entity.d.ts.map +1 -1
- package/dist/adapters/database/domains/client-role/entity.mjs +37 -17
- package/dist/adapters/database/domains/client-role/entity.mjs.map +1 -1
- package/dist/adapters/database/domains/client-scope/entity.d.ts.map +1 -1
- package/dist/adapters/database/domains/client-scope/entity.mjs +30 -14
- package/dist/adapters/database/domains/client-scope/entity.mjs.map +1 -1
- package/dist/adapters/database/domains/consent/entity.d.ts.map +1 -1
- package/dist/adapters/database/domains/consent/entity.mjs +34 -18
- package/dist/adapters/database/domains/consent/entity.mjs.map +1 -1
- package/dist/adapters/database/domains/event/entity.d.ts +1 -0
- package/dist/adapters/database/domains/event/entity.d.ts.map +1 -1
- package/dist/adapters/database/domains/event/entity.mjs +48 -23
- package/dist/adapters/database/domains/event/entity.mjs.map +1 -1
- package/dist/adapters/database/domains/identity-provider/entity.d.ts.map +1 -1
- package/dist/adapters/database/domains/identity-provider/entity.mjs +43 -23
- package/dist/adapters/database/domains/identity-provider/entity.mjs.map +1 -1
- package/dist/adapters/database/domains/identity-provider-account/entity.d.ts.map +1 -1
- package/dist/adapters/database/domains/identity-provider-account/entity.mjs +50 -22
- package/dist/adapters/database/domains/identity-provider-account/entity.mjs.map +1 -1
- package/dist/adapters/database/domains/identity-provider-attribute/entity.d.ts.map +1 -1
- package/dist/adapters/database/domains/identity-provider-attribute/entity.mjs +14 -6
- package/dist/adapters/database/domains/identity-provider-attribute/entity.mjs.map +1 -1
- package/dist/adapters/database/domains/identity-provider-attribute-mapping/entity.d.ts.map +1 -1
- package/dist/adapters/database/domains/identity-provider-attribute-mapping/entity.mjs +5 -1
- package/dist/adapters/database/domains/identity-provider-attribute-mapping/entity.mjs.map +1 -1
- package/dist/adapters/database/domains/identity-provider-permission-mapping/entity.d.ts.map +1 -1
- package/dist/adapters/database/domains/identity-provider-permission-mapping/entity.mjs +18 -6
- package/dist/adapters/database/domains/identity-provider-permission-mapping/entity.mjs.map +1 -1
- package/dist/adapters/database/domains/identity-provider-role-mapping/entity.d.ts.map +1 -1
- package/dist/adapters/database/domains/identity-provider-role-mapping/entity.mjs +34 -14
- package/dist/adapters/database/domains/identity-provider-role-mapping/entity.mjs.map +1 -1
- package/dist/adapters/database/domains/key/entity.d.ts.map +1 -1
- package/dist/adapters/database/domains/key/entity.mjs +35 -19
- package/dist/adapters/database/domains/key/entity.mjs.map +1 -1
- package/dist/adapters/database/domains/permission/entity.d.ts.map +1 -1
- package/dist/adapters/database/domains/permission/entity.mjs +35 -19
- package/dist/adapters/database/domains/permission/entity.mjs.map +1 -1
- package/dist/adapters/database/domains/permission-policy/entity.d.ts.map +1 -1
- package/dist/adapters/database/domains/permission-policy/entity.mjs +37 -17
- package/dist/adapters/database/domains/permission-policy/entity.mjs.map +1 -1
- package/dist/adapters/database/domains/policy/entity.d.ts.map +1 -1
- package/dist/adapters/database/domains/policy/entity.mjs +51 -27
- package/dist/adapters/database/domains/policy/entity.mjs.map +1 -1
- package/dist/adapters/database/domains/policy-attribute/entity.d.ts.map +1 -1
- package/dist/adapters/database/domains/policy-attribute/entity.mjs +14 -6
- package/dist/adapters/database/domains/policy-attribute/entity.mjs.map +1 -1
- package/dist/adapters/database/domains/realm/entity.d.ts.map +1 -1
- package/dist/adapters/database/domains/realm/entity.mjs +36 -20
- package/dist/adapters/database/domains/realm/entity.mjs.map +1 -1
- package/dist/adapters/database/domains/role/entity.d.ts.map +1 -1
- package/dist/adapters/database/domains/role/entity.mjs +44 -24
- package/dist/adapters/database/domains/role/entity.mjs.map +1 -1
- package/dist/adapters/database/domains/role-attribute/entity.d.ts.map +1 -1
- package/dist/adapters/database/domains/role-attribute/entity.mjs +30 -14
- package/dist/adapters/database/domains/role-attribute/entity.mjs.map +1 -1
- package/dist/adapters/database/domains/role-permission/entity.d.ts.map +1 -1
- package/dist/adapters/database/domains/role-permission/entity.mjs +45 -21
- package/dist/adapters/database/domains/role-permission/entity.mjs.map +1 -1
- package/dist/adapters/database/domains/scope/entity.d.ts.map +1 -1
- package/dist/adapters/database/domains/scope/entity.mjs +35 -19
- package/dist/adapters/database/domains/scope/entity.mjs.map +1 -1
- package/dist/adapters/database/domains/session/entity.d.ts.map +1 -1
- package/dist/adapters/database/domains/session/entity.mjs +63 -31
- package/dist/adapters/database/domains/session/entity.mjs.map +1 -1
- package/dist/adapters/database/domains/session-token/entity.d.ts +4 -1
- package/dist/adapters/database/domains/session-token/entity.d.ts.map +1 -1
- package/dist/adapters/database/domains/session-token/entity.mjs +40 -11
- package/dist/adapters/database/domains/session-token/entity.mjs.map +1 -1
- package/dist/adapters/database/domains/trust-anchor/entity.d.ts.map +1 -1
- package/dist/adapters/database/domains/trust-anchor/entity.mjs +25 -13
- package/dist/adapters/database/domains/trust-anchor/entity.mjs.map +1 -1
- package/dist/adapters/database/domains/user/entity.d.ts.map +1 -1
- package/dist/adapters/database/domains/user/entity.mjs +58 -34
- package/dist/adapters/database/domains/user/entity.mjs.map +1 -1
- package/dist/adapters/database/domains/user-attribute/entity.d.ts.map +1 -1
- package/dist/adapters/database/domains/user-attribute/entity.mjs +27 -11
- package/dist/adapters/database/domains/user-attribute/entity.mjs.map +1 -1
- package/dist/adapters/database/domains/user-authenticator/entity.d.ts.map +1 -1
- package/dist/adapters/database/domains/user-authenticator/entity.mjs +43 -23
- package/dist/adapters/database/domains/user-authenticator/entity.mjs.map +1 -1
- package/dist/adapters/database/domains/user-permission/entity.d.ts.map +1 -1
- package/dist/adapters/database/domains/user-permission/entity.mjs +45 -21
- package/dist/adapters/database/domains/user-permission/entity.mjs.map +1 -1
- package/dist/adapters/database/domains/user-role/entity.d.ts.map +1 -1
- package/dist/adapters/database/domains/user-role/entity.mjs +37 -17
- package/dist/adapters/database/domains/user-role/entity.mjs.map +1 -1
- package/dist/adapters/database/errors/driver.d.ts +9 -0
- package/dist/adapters/database/errors/driver.d.ts.map +1 -1
- package/dist/adapters/database/errors/driver.mjs +20 -1
- package/dist/adapters/database/errors/driver.mjs.map +1 -1
- package/dist/adapters/database/errors/index.mjs +2 -2
- package/dist/adapters/database/helpers/index.mjs +2 -2
- package/dist/adapters/database/helpers/is-supported.d.ts +7 -0
- package/dist/adapters/database/helpers/is-supported.d.ts.map +1 -1
- package/dist/adapters/database/helpers/is-supported.mjs +9 -1
- package/dist/adapters/database/helpers/is-supported.mjs.map +1 -1
- package/dist/adapters/database/index.mjs +3 -3
- package/dist/adapters/database/migrations/mysql/1785871780234-AlignSchemaWithEntityMetadata.d.ts +66 -0
- package/dist/adapters/database/migrations/mysql/1785871780234-AlignSchemaWithEntityMetadata.d.ts.map +1 -0
- package/dist/adapters/database/migrations/mysql/1785871780234-AlignSchemaWithEntityMetadata.mjs +181 -0
- package/dist/adapters/database/migrations/mysql/1785871780234-AlignSchemaWithEntityMetadata.mjs.map +1 -0
- package/dist/adapters/database/migrations/mysql/1786436332251-QueryIndexes.d.ts +44 -0
- package/dist/adapters/database/migrations/mysql/1786436332251-QueryIndexes.d.ts.map +1 -0
- package/dist/adapters/database/migrations/mysql/1786436332251-QueryIndexes.mjs +1294 -0
- package/dist/adapters/database/migrations/mysql/1786436332251-QueryIndexes.mjs.map +1 -0
- package/dist/adapters/database/migrations/postgres/1785871780234-AlignSchemaWithEntityMetadata.d.ts +43 -0
- package/dist/adapters/database/migrations/postgres/1785871780234-AlignSchemaWithEntityMetadata.d.ts.map +1 -0
- package/dist/adapters/database/migrations/postgres/1785871780234-AlignSchemaWithEntityMetadata.mjs +120 -0
- package/dist/adapters/database/migrations/postgres/1785871780234-AlignSchemaWithEntityMetadata.mjs.map +1 -0
- package/dist/adapters/database/migrations/postgres/1786436332251-QueryIndexes.d.ts +44 -0
- package/dist/adapters/database/migrations/postgres/1786436332251-QueryIndexes.d.ts.map +1 -0
- package/dist/adapters/database/migrations/postgres/1786436332251-QueryIndexes.mjs +987 -0
- package/dist/adapters/database/migrations/postgres/1786436332251-QueryIndexes.mjs.map +1 -0
- package/dist/adapters/http/controllers/entities/identity-provider/module.d.ts +22 -4
- package/dist/adapters/http/controllers/entities/identity-provider/module.d.ts.map +1 -1
- package/dist/adapters/http/controllers/entities/identity-provider/module.mjs +190 -47
- package/dist/adapters/http/controllers/entities/identity-provider/module.mjs.map +1 -1
- package/dist/adapters/http/controllers/entities/identity-provider/types.d.ts +5 -2
- package/dist/adapters/http/controllers/entities/identity-provider/types.d.ts.map +1 -1
- package/dist/adapters/http/controllers/entities/identity-provider-account/index.d.ts.map +1 -0
- package/dist/adapters/http/controllers/entities/identity-provider-account/index.mjs +5 -0
- package/dist/adapters/http/controllers/entities/identity-provider-account/module.d.ts +15 -0
- package/dist/adapters/http/controllers/entities/identity-provider-account/module.d.ts.map +1 -0
- package/dist/adapters/http/controllers/entities/identity-provider-account/module.mjs +94 -0
- package/dist/adapters/http/controllers/entities/identity-provider-account/module.mjs.map +1 -0
- package/dist/adapters/http/controllers/entities/index.d.ts +2 -0
- package/dist/adapters/http/controllers/entities/index.d.ts.map +1 -1
- package/dist/adapters/http/controllers/entities/index.mjs +5 -1
- package/dist/adapters/http/controllers/entities/session-token/index.d.ts +2 -0
- package/dist/adapters/http/controllers/entities/session-token/index.d.ts.map +1 -0
- package/dist/adapters/http/controllers/entities/session-token/index.mjs +5 -0
- package/dist/adapters/http/controllers/entities/session-token/module.d.ts +23 -0
- package/dist/adapters/http/controllers/entities/session-token/module.d.ts.map +1 -0
- package/dist/adapters/http/controllers/entities/session-token/module.mjs +112 -0
- package/dist/adapters/http/controllers/entities/session-token/module.mjs.map +1 -0
- package/dist/adapters/http/controllers/index.mjs +3 -1
- package/dist/adapters/http/controllers/workflows/authenticator-challenge/module.d.ts.map +1 -1
- package/dist/adapters/http/controllers/workflows/authenticator-challenge/module.mjs +1 -0
- package/dist/adapters/http/controllers/workflows/authenticator-challenge/module.mjs.map +1 -1
- package/dist/adapters/http/index.mjs +3 -1
- package/dist/adapters/http/middleware/built-in/error.d.ts.map +1 -1
- package/dist/adapters/http/middleware/built-in/error.mjs +4 -3
- package/dist/adapters/http/middleware/built-in/error.mjs.map +1 -1
- package/dist/adapters/http/request/event-context.d.ts.map +1 -1
- package/dist/adapters/http/request/event-context.mjs +2 -0
- package/dist/adapters/http/request/event-context.mjs.map +1 -1
- package/dist/app/index.mjs +4 -2
- package/dist/app/modules/database/index.mjs +2 -1
- package/dist/app/modules/database/repositories/identity-provider-account/index.d.ts +2 -0
- package/dist/app/modules/database/repositories/identity-provider-account/index.d.ts.map +1 -0
- package/dist/app/modules/database/repositories/identity-provider-account/index.mjs +5 -0
- package/dist/app/modules/database/repositories/identity-provider-account/repository.d.ts +18 -0
- package/dist/app/modules/database/repositories/identity-provider-account/repository.d.ts.map +1 -0
- package/dist/app/modules/database/repositories/identity-provider-account/repository.mjs +69 -0
- package/dist/app/modules/database/repositories/identity-provider-account/repository.mjs.map +1 -0
- package/dist/app/modules/database/repositories/index.d.ts +1 -0
- package/dist/app/modules/database/repositories/index.d.ts.map +1 -1
- package/dist/app/modules/database/repositories/index.mjs +3 -1
- package/dist/app/modules/database/repositories/key/repository.d.ts +23 -0
- package/dist/app/modules/database/repositories/key/repository.d.ts.map +1 -1
- package/dist/app/modules/database/repositories/key/repository.mjs +39 -3
- package/dist/app/modules/database/repositories/key/repository.mjs.map +1 -1
- package/dist/app/modules/database/repositories/schema-validation.d.ts +14 -6
- package/dist/app/modules/database/repositories/schema-validation.d.ts.map +1 -1
- package/dist/app/modules/database/repositories/schema-validation.mjs +18 -6
- package/dist/app/modules/database/repositories/schema-validation.mjs.map +1 -1
- package/dist/app/modules/http/modules/controller.d.ts +3 -1
- package/dist/app/modules/http/modules/controller.d.ts.map +1 -1
- package/dist/app/modules/http/modules/controller.mjs +39 -2
- package/dist/app/modules/http/modules/controller.mjs.map +1 -1
- package/dist/app/modules/identity/constants.d.ts +2 -1
- package/dist/app/modules/identity/constants.d.ts.map +1 -1
- package/dist/app/modules/identity/constants.mjs +1 -0
- package/dist/app/modules/identity/constants.mjs.map +1 -1
- package/dist/app/modules/identity/index.mjs +3 -2
- package/dist/app/modules/identity/module.d.ts.map +1 -1
- package/dist/app/modules/identity/module.mjs +9 -2
- package/dist/app/modules/identity/module.mjs.map +1 -1
- package/dist/app/modules/identity/repositories/constants.d.ts +4 -0
- package/dist/app/modules/identity/repositories/constants.d.ts.map +1 -0
- package/dist/app/modules/identity/repositories/constants.mjs +12 -0
- package/dist/app/modules/identity/repositories/constants.mjs.map +1 -0
- package/dist/app/modules/identity/repositories/index.d.ts +1 -0
- package/dist/app/modules/identity/repositories/index.d.ts.map +1 -1
- package/dist/app/modules/identity/repositories/index.mjs +3 -2
- package/dist/app/modules/identity/repositories/provider/index.d.ts +1 -1
- package/dist/app/modules/identity/repositories/provider/index.d.ts.map +1 -1
- package/dist/app/modules/identity/repositories/provider/index.mjs +2 -3
- package/dist/app/modules/identity/repositories/provider/link.d.ts +9 -0
- package/dist/app/modules/identity/repositories/provider/link.d.ts.map +1 -0
- package/dist/app/modules/identity/repositories/provider/link.mjs +34 -0
- package/dist/app/modules/identity/repositories/provider/link.mjs.map +1 -0
- package/dist/app/modules/index.mjs +4 -2
- package/dist/app/modules/logger/module.d.ts.map +1 -1
- package/dist/app/modules/logger/module.mjs +1 -0
- package/dist/app/modules/logger/module.mjs.map +1 -1
- package/dist/app/modules/oauth2/repositories/session-token/repository.d.ts +25 -1
- package/dist/app/modules/oauth2/repositories/session-token/repository.d.ts.map +1 -1
- package/dist/app/modules/oauth2/repositories/session-token/repository.mjs +70 -1
- package/dist/app/modules/oauth2/repositories/session-token/repository.mjs.map +1 -1
- package/dist/app/modules/provisioning/module.d.ts.map +1 -1
- package/dist/app/modules/provisioning/module.mjs +3 -1
- package/dist/app/modules/provisioning/module.mjs.map +1 -1
- package/dist/app/modules/provisioning/sources/default/module.d.ts.map +1 -1
- package/dist/app/modules/provisioning/sources/default/module.mjs +1 -0
- package/dist/app/modules/provisioning/sources/default/module.mjs.map +1 -1
- package/dist/core/entities/client/schema.d.ts.map +1 -1
- package/dist/core/entities/client/schema.mjs +29 -10
- package/dist/core/entities/client/schema.mjs.map +1 -1
- package/dist/core/entities/client-permission/schema.d.ts.map +1 -1
- package/dist/core/entities/client-permission/schema.mjs +29 -6
- package/dist/core/entities/client-permission/schema.mjs.map +1 -1
- package/dist/core/entities/client-role/schema.d.ts.map +1 -1
- package/dist/core/entities/client-role/schema.mjs +27 -6
- package/dist/core/entities/client-role/schema.mjs.map +1 -1
- package/dist/core/entities/client-scope/schema.d.ts.map +1 -1
- package/dist/core/entities/client-scope/schema.mjs +19 -5
- package/dist/core/entities/client-scope/schema.mjs.map +1 -1
- package/dist/core/entities/consent/schema.d.ts.map +1 -1
- package/dist/core/entities/consent/schema.mjs +28 -6
- package/dist/core/entities/consent/schema.mjs.map +1 -1
- package/dist/core/entities/event/entity-event-handler.d.ts.map +1 -1
- package/dist/core/entities/event/entity-event-handler.mjs +2 -0
- package/dist/core/entities/event/entity-event-handler.mjs.map +1 -1
- package/dist/core/entities/event/sanitize.d.ts.map +1 -1
- package/dist/core/entities/event/sanitize.mjs +7 -4
- package/dist/core/entities/event/sanitize.mjs.map +1 -1
- package/dist/core/entities/event/schema.d.ts.map +1 -1
- package/dist/core/entities/event/schema.mjs +45 -16
- package/dist/core/entities/event/schema.mjs.map +1 -1
- package/dist/core/entities/event/service.d.ts.map +1 -1
- package/dist/core/entities/event/service.mjs +2 -0
- package/dist/core/entities/event/service.mjs.map +1 -1
- package/dist/core/entities/event/types.d.ts +2 -0
- package/dist/core/entities/event/types.d.ts.map +1 -1
- package/dist/core/entities/identity-provider/schema.d.ts.map +1 -1
- package/dist/core/entities/identity-provider/schema.mjs +29 -11
- package/dist/core/entities/identity-provider/schema.mjs.map +1 -1
- package/dist/core/entities/identity-provider-account/error.d.ts +7 -0
- package/dist/core/entities/identity-provider-account/error.d.ts.map +1 -0
- package/dist/core/entities/identity-provider-account/error.mjs +24 -0
- package/dist/core/entities/identity-provider-account/error.mjs.map +1 -0
- package/dist/core/entities/identity-provider-account/index.d.ts +5 -0
- package/dist/core/entities/identity-provider-account/index.d.ts.map +1 -0
- package/dist/core/entities/identity-provider-account/index.mjs +8 -0
- package/dist/core/entities/identity-provider-account/schema.d.ts +3 -0
- package/dist/core/entities/identity-provider-account/schema.d.ts.map +1 -0
- package/dist/core/entities/identity-provider-account/schema.mjs +52 -0
- package/dist/core/entities/identity-provider-account/schema.mjs.map +1 -0
- package/dist/core/entities/identity-provider-account/service.d.ts +24 -0
- package/dist/core/entities/identity-provider-account/service.d.ts.map +1 -0
- package/dist/core/entities/identity-provider-account/service.mjs +129 -0
- package/dist/core/entities/identity-provider-account/service.mjs.map +1 -0
- package/dist/core/entities/identity-provider-account/types.d.ts +69 -0
- package/dist/core/entities/identity-provider-account/types.d.ts.map +1 -0
- package/dist/core/entities/identity-provider-account/types.mjs +17 -0
- package/dist/core/entities/identity-provider-account/types.mjs.map +1 -0
- package/dist/core/entities/identity-provider-role-mapping/schema.d.ts.map +1 -1
- package/dist/core/entities/identity-provider-role-mapping/schema.mjs +27 -6
- package/dist/core/entities/identity-provider-role-mapping/schema.mjs.map +1 -1
- package/dist/core/entities/index.d.ts +2 -0
- package/dist/core/entities/index.d.ts.map +1 -1
- package/dist/core/entities/index.mjs +9 -1
- package/dist/core/entities/key/schema.d.ts.map +1 -1
- package/dist/core/entities/key/schema.mjs +39 -17
- package/dist/core/entities/key/schema.mjs.map +1 -1
- package/dist/core/entities/key/service.d.ts.map +1 -1
- package/dist/core/entities/key/service.mjs +1 -0
- package/dist/core/entities/key/service.mjs.map +1 -1
- package/dist/core/entities/permission/schema.d.ts.map +1 -1
- package/dist/core/entities/permission/schema.mjs +34 -13
- package/dist/core/entities/permission/schema.mjs.map +1 -1
- package/dist/core/entities/permission-policy/schema.d.ts.map +1 -1
- package/dist/core/entities/permission-policy/schema.mjs +27 -6
- package/dist/core/entities/permission-policy/schema.mjs.map +1 -1
- package/dist/core/entities/policy/schema.d.ts.map +1 -1
- package/dist/core/entities/policy/schema.mjs +31 -12
- package/dist/core/entities/policy/schema.mjs.map +1 -1
- package/dist/core/entities/realm/schema.d.ts.map +1 -1
- package/dist/core/entities/realm/schema.mjs +26 -12
- package/dist/core/entities/realm/schema.mjs.map +1 -1
- package/dist/core/entities/role/schema.d.ts.map +1 -1
- package/dist/core/entities/role/schema.mjs +36 -14
- package/dist/core/entities/role/schema.mjs.map +1 -1
- package/dist/core/entities/role-attribute/schema.d.ts.map +1 -1
- package/dist/core/entities/role-attribute/schema.mjs +28 -14
- package/dist/core/entities/role-attribute/schema.mjs.map +1 -1
- package/dist/core/entities/role-permission/schema.d.ts.map +1 -1
- package/dist/core/entities/role-permission/schema.mjs +29 -6
- package/dist/core/entities/role-permission/schema.mjs.map +1 -1
- package/dist/core/entities/scope/schema.d.ts.map +1 -1
- package/dist/core/entities/scope/schema.mjs +28 -12
- package/dist/core/entities/scope/schema.mjs.map +1 -1
- package/dist/core/entities/session/schema.d.ts.map +1 -1
- package/dist/core/entities/session/schema.mjs +41 -9
- package/dist/core/entities/session/schema.mjs.map +1 -1
- package/dist/core/entities/session-token/index.d.ts +4 -0
- package/dist/core/entities/session-token/index.d.ts.map +1 -0
- package/dist/core/entities/session-token/index.mjs +6 -0
- package/dist/core/entities/session-token/schema.d.ts +12 -0
- package/dist/core/entities/session-token/schema.d.ts.map +1 -0
- package/dist/core/entities/session-token/schema.mjs +66 -0
- package/dist/core/entities/session-token/schema.mjs.map +1 -0
- package/dist/core/entities/session-token/service.d.ts +70 -0
- package/dist/core/entities/session-token/service.d.ts.map +1 -0
- package/dist/core/entities/session-token/service.mjs +216 -0
- package/dist/core/entities/session-token/service.mjs.map +1 -0
- package/dist/core/entities/session-token/types.d.ts +37 -0
- package/dist/core/entities/session-token/types.d.ts.map +1 -0
- package/dist/core/entities/session-token/types.mjs +4 -0
- package/dist/core/entities/trust-anchor/schema.d.ts.map +1 -1
- package/dist/core/entities/trust-anchor/schema.mjs +27 -13
- package/dist/core/entities/trust-anchor/schema.mjs.map +1 -1
- package/dist/core/entities/trust-anchor/service.d.ts.map +1 -1
- package/dist/core/entities/trust-anchor/service.mjs +1 -0
- package/dist/core/entities/trust-anchor/service.mjs.map +1 -1
- package/dist/core/entities/user/schema.d.ts.map +1 -1
- package/dist/core/entities/user/schema.mjs +29 -12
- package/dist/core/entities/user/schema.mjs.map +1 -1
- package/dist/core/entities/user-attribute/schema.d.ts.map +1 -1
- package/dist/core/entities/user-attribute/schema.mjs +28 -14
- package/dist/core/entities/user-attribute/schema.mjs.map +1 -1
- package/dist/core/entities/user-authenticator/schema.d.ts.map +1 -1
- package/dist/core/entities/user-authenticator/schema.mjs +29 -12
- package/dist/core/entities/user-authenticator/schema.mjs.map +1 -1
- package/dist/core/entities/user-authenticator/service.d.ts +2 -1
- package/dist/core/entities/user-authenticator/service.d.ts.map +1 -1
- package/dist/core/entities/user-authenticator/service.mjs +5 -0
- package/dist/core/entities/user-authenticator/service.mjs.map +1 -1
- package/dist/core/entities/user-authenticator/types.d.ts +7 -1
- package/dist/core/entities/user-authenticator/types.d.ts.map +1 -1
- package/dist/core/entities/user-authenticator/types.mjs.map +1 -1
- package/dist/core/entities/user-permission/schema.d.ts.map +1 -1
- package/dist/core/entities/user-permission/schema.mjs +29 -6
- package/dist/core/entities/user-permission/schema.mjs.map +1 -1
- package/dist/core/entities/user-role/schema.d.ts.map +1 -1
- package/dist/core/entities/user-role/schema.mjs +27 -6
- package/dist/core/entities/user-role/schema.mjs.map +1 -1
- package/dist/core/identity/index.mjs +3 -1
- package/dist/core/identity/provider/account/constants.d.ts +10 -0
- package/dist/core/identity/provider/account/constants.d.ts.map +1 -0
- package/dist/core/identity/provider/account/constants.mjs +16 -0
- package/dist/core/identity/provider/account/constants.mjs.map +1 -0
- package/dist/core/identity/provider/account/error.d.ts +7 -0
- package/dist/core/identity/provider/account/error.d.ts.map +1 -0
- package/dist/core/identity/provider/account/error.mjs +24 -0
- package/dist/core/identity/provider/account/error.mjs.map +1 -0
- package/dist/core/identity/provider/account/index.d.ts +2 -0
- package/dist/core/identity/provider/account/index.d.ts.map +1 -1
- package/dist/core/identity/provider/account/index.mjs +3 -1
- package/dist/core/identity/provider/account/module.d.ts +2 -0
- package/dist/core/identity/provider/account/module.d.ts.map +1 -1
- package/dist/core/identity/provider/account/module.mjs +30 -0
- package/dist/core/identity/provider/account/module.mjs.map +1 -1
- package/dist/core/identity/provider/account/types.d.ts +44 -7
- package/dist/core/identity/provider/account/types.d.ts.map +1 -1
- package/dist/core/identity/provider/authentication/protocols/oauth2/module.d.ts +19 -0
- package/dist/core/identity/provider/authentication/protocols/oauth2/module.d.ts.map +1 -1
- package/dist/core/identity/provider/authentication/protocols/oauth2/module.mjs +60 -3
- package/dist/core/identity/provider/authentication/protocols/oauth2/module.mjs.map +1 -1
- package/dist/core/identity/provider/authentication/protocols/oauth2/types.d.ts +9 -0
- package/dist/core/identity/provider/authentication/protocols/oauth2/types.d.ts.map +1 -1
- package/dist/core/identity/provider/authentication/protocols/open-id/module.d.ts +0 -3
- package/dist/core/identity/provider/authentication/protocols/open-id/module.d.ts.map +1 -1
- package/dist/core/identity/provider/authentication/protocols/open-id/module.mjs +0 -17
- package/dist/core/identity/provider/authentication/protocols/open-id/module.mjs.map +1 -1
- package/dist/core/identity/provider/index.mjs +3 -1
- package/dist/core/index.mjs +11 -2
- package/dist/core/oauth2/authorization/code-request/verifier/module.d.ts.map +1 -1
- package/dist/core/oauth2/authorization/code-request/verifier/module.mjs +2 -1
- package/dist/core/oauth2/authorization/code-request/verifier/module.mjs.map +1 -1
- package/dist/core/oauth2/authorization/module.d.ts.map +1 -1
- package/dist/core/oauth2/authorization/module.mjs +2 -0
- package/dist/core/oauth2/authorization/module.mjs.map +1 -1
- package/dist/core/oauth2/authorization/state/types.d.ts +11 -0
- package/dist/core/oauth2/authorization/state/types.d.ts.map +1 -1
- package/dist/core/oauth2/end-session/service.mjs +2 -2
- package/dist/core/oauth2/end-session/service.mjs.map +1 -1
- package/dist/core/oauth2/grant-types/authorize.d.ts.map +1 -1
- package/dist/core/oauth2/grant-types/authorize.mjs +1 -5
- package/dist/core/oauth2/grant-types/authorize.mjs.map +1 -1
- package/dist/core/oauth2/grant-types/password.mjs +2 -5
- package/dist/core/oauth2/grant-types/password.mjs.map +1 -1
- package/dist/core/oauth2/grant-types/refresh-token.d.ts.map +1 -1
- package/dist/core/oauth2/grant-types/refresh-token.mjs +37 -24
- package/dist/core/oauth2/grant-types/refresh-token.mjs.map +1 -1
- package/dist/core/oauth2/index.mjs +3 -1
- package/dist/core/oauth2/mfa-login/module.d.ts.map +1 -1
- package/dist/core/oauth2/mfa-login/module.mjs +4 -7
- package/dist/core/oauth2/mfa-login/module.mjs.map +1 -1
- package/dist/core/oauth2/session-token/error.d.ts +36 -0
- package/dist/core/oauth2/session-token/error.d.ts.map +1 -0
- package/dist/core/oauth2/session-token/error.mjs +49 -0
- package/dist/core/oauth2/session-token/error.mjs.map +1 -0
- package/dist/core/oauth2/session-token/index.d.ts +1 -0
- package/dist/core/oauth2/session-token/index.d.ts.map +1 -1
- package/dist/core/oauth2/session-token/index.mjs +2 -1
- package/dist/core/oauth2/session-token/types.d.ts +40 -0
- package/dist/core/oauth2/session-token/types.d.ts.map +1 -1
- package/dist/core/oauth2/token/issuer/access/module.d.ts.map +1 -1
- package/dist/core/oauth2/token/issuer/access/module.mjs +1 -0
- package/dist/core/oauth2/token/issuer/access/module.mjs.map +1 -1
- package/dist/core/oauth2/token/issuer/base.d.ts +1 -1
- package/dist/core/oauth2/token/issuer/base.d.ts.map +1 -1
- package/dist/core/oauth2/token/issuer/base.mjs.map +1 -1
- package/dist/core/oauth2/token/issuer/refresh/module.d.ts.map +1 -1
- package/dist/core/oauth2/token/issuer/refresh/module.mjs +1 -0
- package/dist/core/oauth2/token/issuer/refresh/module.mjs.map +1 -1
- package/dist/core/query/index.mjs +2 -2
- package/dist/core/query/module.d.ts +19 -9
- package/dist/core/query/module.d.ts.map +1 -1
- package/dist/core/query/module.mjs +22 -10
- package/dist/core/query/module.mjs.map +1 -1
- package/dist/index.mjs +8 -4
- package/dist/swagger.json +961 -132
- package/dist/utils/error.d.ts +20 -3
- package/dist/utils/error.d.ts.map +1 -1
- package/dist/utils/error.mjs +102 -5
- package/dist/utils/error.mjs.map +1 -1
- package/dist/utils/index.mjs +2 -2
- package/package.json +23 -21
- package/dist/app/modules/identity/repositories/provider/account/index.d.ts.map +0 -1
- package/dist/app/modules/identity/repositories/provider/account/index.mjs +0 -5
- package/dist/app/modules/identity/repositories/provider/account/module.d.ts +0 -10
- package/dist/app/modules/identity/repositories/provider/account/module.d.ts.map +0 -1
- package/dist/app/modules/identity/repositories/provider/account/module.mjs +0 -28
- package/dist/app/modules/identity/repositories/provider/account/module.mjs.map +0 -1
- /package/dist/{app/modules/identity/repositories/provider/account → adapters/http/controllers/entities/identity-provider-account}/index.d.ts +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.mjs","names":["defineSchema","EntityType","createRelationsReadGate","schemaMapping","user","USER","role","ROLE","userRoleSchema","name","USER_ROLE","fields","default","filters","allowed","relations","validate","
|
|
1
|
+
{"version":3,"file":"schema.mjs","names":["defineSchema","EntityType","createRelationsReadGate","schemaMapping","user","USER","role","ROLE","userRoleSchema","name","USER_ROLE","indexes","fields","default","filters","allowed","indexed","relations","validate","sorts","pagination","maxLimit"],"sources":["../../../../src/core/entities/user-role/schema.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 { defineSchema } from '@rapiq/core';\nimport type { UserRole } from '@authup/core-kit';\nimport { EntityType } from '@authup/core-kit';\nimport { createRelationsReadGate } from '../../query/relations.ts';\n\nconst schemaMapping = { user: EntityType.USER, role: EntityType.ROLE };\n\nexport const userRoleSchema = defineSchema<UserRole>({\n name: EntityType.USER_ROLE,\n indexes: [\n ['id'],\n ['roleId', 'userId'],\n ['userId'],\n ['roleRealmId'],\n ['userRealmId'],\n ['createdAt'],\n ['updatedAt'],\n ],\n // `default` pins an explicit root projection: an include= decodes the\n // relation's fields, and the adapter's select-replace would otherwise\n // drop every root column (incl. the id the DISTINCT wrapper needs).\n fields: {\n default: [\n 'id',\n 'roleId',\n 'roleRealmId',\n 'userId',\n 'userRealmId',\n 'createdAt',\n 'updatedAt',\n ],\n },\n filters: { allowed: ['roleId', 'userId', 'id', 'roleRealmId', 'userRealmId'], indexed: true },\n relations: { allowed: ['user', 'role'], validate: createRelationsReadGate(schemaMapping) },\n sorts: { allowed: ['id', 'createdAt', 'updatedAt'], indexed: true },\n pagination: { maxLimit: 50 },\n schemaMapping,\n});\n"],"mappings":";;;;;;;AAYA,MAAMG,gBAAgB;CAAEC,MAAMH,WAAWI;CAAMC,MAAML,WAAWM;AAAK;AAErE,MAAaC,iBAAiBR,aAAuB;CACjDS,MAAMR,WAAWS;CACjBC,SAAS;EACL,CAAC,IAAK;EACN,CAAC,UAAU,QAAS;EACpB,CAAC,QAAS;EACV,CAAC,aAAc;EACf,CAAC,aAAc;EACf,CAAC,WAAY;EACb,CAAC,WAAY;CAChB;CAIDC,QAAQ,EACJC,SAAS;EACL;EACA;EACA;EACA;EACA;EACA;EACA;CACH,EACL;CACAC,SAAS;EAAEC,SAAS;GAAC;GAAU;GAAU;GAAM;GAAe;EAAc;EAAEC,SAAS;CAAK;CAC5FC,WAAW;EAAEF,SAAS,CAAC,QAAQ,MAAO;EAAEG,UAAUhB,wBAAwBC,aAAAA;CAAe;CACzFgB,OAAO;EAAEJ,SAAS;GAAC;GAAM;GAAa;EAAY;EAAEC,SAAS;CAAK;CAClEI,YAAY,EAAEC,UAAU,GAAG;CAC3BlB;AACJ,CAAA"}
|
|
@@ -11,6 +11,8 @@ 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";
|
|
15
|
+
import { IDENTITY_PROVIDER_ACCOUNT_ALREADY_LINKED_ERROR_INSTANCE, IdentityProviderAccountAlreadyLinkedError, isIdentityProviderAccountAlreadyLinkedError } from "./provider/account/error.mjs";
|
|
14
16
|
import { IdentityProviderMapperOperation } from "./provider/mapper/constants.mjs";
|
|
15
17
|
import { IdentityProviderAccountBaseMapper } from "./provider/mapper/base.mjs";
|
|
16
18
|
import { IdentityProviderAttributeMapper } from "./provider/mapper/attributes/module.mjs";
|
|
@@ -34,4 +36,4 @@ import "./registration/index.mjs";
|
|
|
34
36
|
import { IdentityResolver } from "./resolver/module.mjs";
|
|
35
37
|
import "./resolver/index.mjs";
|
|
36
38
|
import { IdentityRoleProvider } from "./role/module.mjs";
|
|
37
|
-
export { IDENTITY_PROVIDER_LDAP_COLLECTION_AUTHENTICATOR_TOKEN, IdentityPermissionProvider, 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, 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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { ValidationError } from '@authup/errors';
|
|
2
|
+
export declare const IDENTITY_PROVIDER_ACCOUNT_ALREADY_LINKED_ERROR_INSTANCE: unique symbol;
|
|
3
|
+
export declare class IdentityProviderAccountAlreadyLinkedError extends ValidationError {
|
|
4
|
+
constructor();
|
|
5
|
+
}
|
|
6
|
+
export declare function isIdentityProviderAccountAlreadyLinkedError(input: unknown): input is IdentityProviderAccountAlreadyLinkedError;
|
|
7
|
+
//# sourceMappingURL=error.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error.d.ts","sourceRoot":"","sources":["../../../../../src/core/identity/provider/account/error.ts"],"names":[],"mappings":"AAOA,OAAO,EAEH,eAAe,EAIlB,MAAM,gBAAgB,CAAC;AAExB,eAAO,MAAM,uDAAuD,eAA8E,CAAC;AAEnJ,qBAAa,yCAA0C,SAAQ,eAAe;;CAQ7E;AAED,wBAAgB,2CAA2C,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,yCAAyC,CAI9H"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import "node:path";
|
|
2
|
+
import "node:url";
|
|
3
|
+
import.meta.url;
|
|
4
|
+
import { ErrorCode, ValidationError, isAuthupError, markInstanceof, matchesInstanceof } from "@authup/errors";
|
|
5
|
+
//#region src/core/identity/provider/account/error.ts
|
|
6
|
+
const IDENTITY_PROVIDER_ACCOUNT_ALREADY_LINKED_ERROR_INSTANCE = Symbol.for("@authup/server-core/IdentityProviderAccountAlreadyLinkedError");
|
|
7
|
+
var IdentityProviderAccountAlreadyLinkedError = class extends ValidationError {
|
|
8
|
+
constructor() {
|
|
9
|
+
super({
|
|
10
|
+
code: ErrorCode.IDENTITY_PROVIDER_ACCOUNT_ALREADY_LINKED,
|
|
11
|
+
message: "The external account is already linked to another user."
|
|
12
|
+
});
|
|
13
|
+
markInstanceof(this, IDENTITY_PROVIDER_ACCOUNT_ALREADY_LINKED_ERROR_INSTANCE);
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
function isIdentityProviderAccountAlreadyLinkedError(input) {
|
|
17
|
+
if (matchesInstanceof(input, IDENTITY_PROVIDER_ACCOUNT_ALREADY_LINKED_ERROR_INSTANCE)) return true;
|
|
18
|
+
if (!isAuthupError(input)) return false;
|
|
19
|
+
return input.code === ErrorCode.IDENTITY_PROVIDER_ACCOUNT_ALREADY_LINKED;
|
|
20
|
+
}
|
|
21
|
+
//#endregion
|
|
22
|
+
export { IDENTITY_PROVIDER_ACCOUNT_ALREADY_LINKED_ERROR_INSTANCE, IdentityProviderAccountAlreadyLinkedError, isIdentityProviderAccountAlreadyLinkedError };
|
|
23
|
+
|
|
24
|
+
//# sourceMappingURL=error.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error.mjs","names":["ErrorCode","ValidationError","isAuthupError","markInstanceof","matchesInstanceof","IDENTITY_PROVIDER_ACCOUNT_ALREADY_LINKED_ERROR_INSTANCE","Symbol","for","IdentityProviderAccountAlreadyLinkedError","code","IDENTITY_PROVIDER_ACCOUNT_ALREADY_LINKED","message","isIdentityProviderAccountAlreadyLinkedError","input"],"sources":["../../../../../src/core/identity/provider/account/error.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 {\n ErrorCode,\n ValidationError,\n isAuthupError,\n markInstanceof,\n matchesInstanceof,\n} from '@authup/errors';\n\nexport const IDENTITY_PROVIDER_ACCOUNT_ALREADY_LINKED_ERROR_INSTANCE = Symbol.for('@authup/server-core/IdentityProviderAccountAlreadyLinkedError');\n\nexport class IdentityProviderAccountAlreadyLinkedError extends ValidationError {\n constructor() {\n super({\n code: ErrorCode.IDENTITY_PROVIDER_ACCOUNT_ALREADY_LINKED,\n message: 'The external account is already linked to another user.',\n });\n markInstanceof(this, IDENTITY_PROVIDER_ACCOUNT_ALREADY_LINKED_ERROR_INSTANCE);\n }\n}\n\nexport function isIdentityProviderAccountAlreadyLinkedError(input: unknown): input is IdentityProviderAccountAlreadyLinkedError {\n if (matchesInstanceof(input, IDENTITY_PROVIDER_ACCOUNT_ALREADY_LINKED_ERROR_INSTANCE)) return true;\n if (!isAuthupError(input)) return false;\n return input.code === ErrorCode.IDENTITY_PROVIDER_ACCOUNT_ALREADY_LINKED;\n}\n"],"mappings":";;;;;AAeA,MAAaK,0DAA0DC,OAAOC,IAAI,+DAAA;AAElF,IAAaC,4CAAb,cAA+DP,gBAAAA;CAC3D,cAAc;EACV,MAAM;GACFQ,MAAMT,UAAUU;GAChBC,SAAS;EACb,CAAA;EACAR,eAAe,MAAME,uDAAAA;CACzB;AACJ;AAEA,SAAgBO,4CAA4CC,OAAc;CACtE,IAAIT,kBAAkBS,OAAOR,uDAAAA,GAA0D,OAAO;CAC9F,IAAI,CAACH,cAAcW,KAAAA,GAAQ,OAAO;CAClC,OAAOA,MAAMJ,SAAST,UAAUU;AACpC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/core/identity/provider/account/index.ts"],"names":[],"mappings":"AAOA,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,5 +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";
|
|
5
|
+
import { IDENTITY_PROVIDER_ACCOUNT_ALREADY_LINKED_ERROR_INSTANCE, IdentityProviderAccountAlreadyLinkedError, isIdentityProviderAccountAlreadyLinkedError } from "./error.mjs";
|
|
4
6
|
import { IdentityProviderAccountManager } from "./module.mjs";
|
|
5
|
-
export { IdentityProviderAccountManager };
|
|
7
|
+
export { IDENTITY_PROVIDER_ACCOUNT_ALREADY_LINKED_ERROR_INSTANCE, IDENTITY_PROVIDER_ACCOUNT_LINK_TTL, IdentityProviderAccountAlreadyLinkedError, IdentityProviderAccountManager, isIdentityProviderAccountAlreadyLinkedError };
|
|
@@ -13,6 +13,8 @@ export declare class IdentityProviderAccountManager implements IIdentityProvider
|
|
|
13
13
|
protected userValidator: UserValidator;
|
|
14
14
|
constructor(ctx: IdentityProviderAccountManagerContext);
|
|
15
15
|
save(identity: IdentityProviderIdentity): Promise<IdentityProviderAccount>;
|
|
16
|
+
link(identity: IdentityProviderIdentity, userId: string): Promise<IdentityProviderAccount>;
|
|
17
|
+
protected pickCandidate(identity: IdentityProviderIdentity, key: keyof User, maxLength: number): string | null;
|
|
16
18
|
saveUser(identity: IdentityProviderIdentity, user?: User): Promise<User>;
|
|
17
19
|
validateAttributes(entity: Record<string, any>, identity: IdentityProviderIdentity, attempts: number): Promise<User | null>;
|
|
18
20
|
savePermissions(identity: IdentityProviderIdentity, user: User): Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../../../../../src/core/identity/provider/account/module.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,uBAAuB,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AACtE,OAAO,EACH,aAAa,EAGhB,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../../../../../src/core/identity/provider/account/module.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,uBAAuB,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AACtE,OAAO,EACH,aAAa,EAGhB,MAAM,kBAAkB,CAAC;AAI1B,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AAEvE,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC;AAElE,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAC;AAE5D,OAAO,KAAK,EAAE,+BAA+B,EAAE,kCAAkC,EAAE,qCAAqC,EAAE,MAAM,YAAY,CAAC;AAE7I,qBAAa,8BAA+B,YAAW,+BAA+B;IAClF,SAAS,CAAC,gBAAgB,EAAG,uBAAuB,CAAC;IAErD,SAAS,CAAC,gBAAgB,EAAG,uBAAuB,CAAC;IAErD,SAAS,CAAC,UAAU,EAAG,uBAAuB,CAAC;IAE/C,SAAS,CAAC,UAAU,EAAG,kCAAkC,CAAC;IAE1D,SAAS,CAAC,cAAc,EAAE,uBAAuB,CAAC;IAElD,SAAS,CAAC,aAAa,EAAG,aAAa,CAAC;gBAE5B,GAAG,EAAE,qCAAqC;IAUhD,IAAI,CAAC,QAAQ,EAAE,wBAAwB,GAAG,OAAO,CAAC,uBAAuB,CAAC;IAmC1E,IAAI,CAAC,QAAQ,EAAE,wBAAwB,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,uBAAuB,CAAC;IAuChG,SAAS,CAAC,aAAa,CACnB,QAAQ,EAAE,wBAAwB,EAClC,GAAG,EAAE,MAAM,IAAI,EACf,SAAS,EAAE,MAAM,GAClB,MAAM,GAAG,IAAI;IAWV,QAAQ,CACV,QAAQ,EAAE,wBAAwB,EAClC,IAAI,CAAC,EAAE,IAAI,GACZ,OAAO,CAAC,IAAI,CAAC;IA0FV,kBAAkB,CACpB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC3B,QAAQ,EAAE,wBAAwB,EAClC,QAAQ,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC;IA+ElB,eAAe,CACjB,QAAQ,EAAE,wBAAwB,EAClC,IAAI,EAAE,IAAI;IAOR,SAAS,CACX,QAAQ,EAAE,wBAAwB,EAClC,IAAI,EAAE,IAAI;CAMjB"}
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import "node:path";
|
|
2
2
|
import "node:url";
|
|
3
3
|
import.meta.url;
|
|
4
|
+
import { IdentityProviderAccountAlreadyLinkedError } from "./error.mjs";
|
|
4
5
|
import { IdentityProviderIdentityOperation } from "../constants.mjs";
|
|
5
6
|
import { IdentityProviderMapperOperation } from "../mapper/constants.mjs";
|
|
6
7
|
import "../mapper/index.mjs";
|
|
7
8
|
import { ValidatorGroup, createNanoID, extendObject } from "@authup/kit";
|
|
8
9
|
import { UserValidator, buildUserFakeEmail, isUserFakeEmail } from "@authup/core-kit";
|
|
10
|
+
import { ValidationError } from "@authup/errors";
|
|
9
11
|
import { isValidupError, stringifyPath } from "validup";
|
|
10
12
|
//#region src/core/identity/provider/account/module.ts
|
|
11
13
|
var IdentityProviderAccountManager = class {
|
|
@@ -48,6 +50,34 @@ var IdentityProviderAccountManager = class {
|
|
|
48
50
|
await this.savePermissions(identity, account.user);
|
|
49
51
|
return account;
|
|
50
52
|
}
|
|
53
|
+
async link(identity, userId) {
|
|
54
|
+
const user = await this.userRepository.findOneById(userId);
|
|
55
|
+
if (!user) throw new ValidationError("The linking user does not exist.");
|
|
56
|
+
if (identity.provider.realmId && user.realmId !== identity.provider.realmId) throw new ValidationError("The provider and user realm do not match.");
|
|
57
|
+
const providerUserName = this.pickCandidate(identity, "name", 256) ?? identity.id.slice(0, 256);
|
|
58
|
+
const providerUserEmail = this.pickCandidate(identity, "email", 512);
|
|
59
|
+
const existing = await this.repository.findOneByProviderIdentity(identity);
|
|
60
|
+
if (existing) {
|
|
61
|
+
if (existing.userId !== userId) throw new IdentityProviderAccountAlreadyLinkedError();
|
|
62
|
+
existing.providerUserName = providerUserName ?? existing.providerUserName;
|
|
63
|
+
existing.providerUserEmail = providerUserEmail ?? existing.providerUserEmail;
|
|
64
|
+
return this.repository.save(existing);
|
|
65
|
+
}
|
|
66
|
+
return this.repository.save({
|
|
67
|
+
providerId: identity.provider.id,
|
|
68
|
+
providerUserId: identity.id,
|
|
69
|
+
providerUserName,
|
|
70
|
+
providerUserEmail: providerUserEmail ?? void 0,
|
|
71
|
+
providerRealmId: identity.provider.realmId,
|
|
72
|
+
userId,
|
|
73
|
+
userRealmId: user.realmId ?? null
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
pickCandidate(identity, key, maxLength) {
|
|
77
|
+
const candidates = identity.attributeCandidates?.[key] || [];
|
|
78
|
+
for (const candidate of candidates) if (typeof candidate === "string" && candidate.length > 0) return candidate.slice(0, maxLength);
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
51
81
|
async saveUser(identity, user) {
|
|
52
82
|
const attributes = await this.attributesMapper.execute(identity);
|
|
53
83
|
const entity = {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"module.mjs","names":["UserValidator","buildUserFakeEmail","isUserFakeEmail","ValidatorGroup","createNanoID","extendObject","isValidupError","stringifyPath","IdentityProviderIdentityOperation","IdentityProviderMapperOperation","IdentityProviderAccountManager","attributesMapper","permissionMapper","roleMapper","repository","userRepository","userValidator","ctx","attributeMapper","save","identity","account","findOneByProviderIdentity","operation","UPDATE","user","saveUser","saveRoles","savePermissions","CREATE","providerId","provider","id","providerUserId","providerUserName","name","providerRealmId","realmId","userId","userRealmId","attributes","execute","entity","attribute","key","value","active","nameLocked","clientId","attributesSelf","validateAttributes","Error","attributesSelfKeys","Object","keys","attributesExtra","entityKeys","entityKey","index","indexOf","output","trim","toLowerCase","attempts","Math","max","attributeCandidates","length","saveOneWithEA","names","shift","run","group","email","e","retry","i","issues","child","pathNormalized","path","Array","isArray","first","rest","push","entities"],"sources":["../../../../../src/core/identity/provider/account/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 { IdentityProviderAccount, User } from '@authup/core-kit';\nimport {\n UserValidator,\n buildUserFakeEmail,\n isUserFakeEmail,\n} from '@authup/core-kit';\nimport { ValidatorGroup, createNanoID, extendObject } from '@authup/kit';\nimport { isValidupError, stringifyPath } from 'validup';\nimport type { IUserIdentityRepository } from '../../entities/index.ts';\nimport { IdentityProviderIdentityOperation } from '../constants.ts';\nimport type { IIdentityProviderMapper } from '../mapper/index.ts';\nimport { IdentityProviderMapperOperation } from '../mapper/index.ts';\nimport type { IdentityProviderIdentity } from '../types.ts';\nimport type { IIdentityProviderAccountManager, IIdentityProviderAccountRepository, IdentityProviderAccountManagerContext } from './types.ts';\n\nexport class IdentityProviderAccountManager implements IIdentityProviderAccountManager {\n protected attributesMapper : IIdentityProviderMapper;\n\n protected permissionMapper : IIdentityProviderMapper;\n\n protected roleMapper : IIdentityProviderMapper;\n\n protected repository : IIdentityProviderAccountRepository;\n\n protected userRepository: IUserIdentityRepository;\n\n protected userValidator : UserValidator;\n\n constructor(ctx: IdentityProviderAccountManagerContext) {\n this.attributesMapper = ctx.attributeMapper;\n this.permissionMapper = ctx.permissionMapper;\n this.roleMapper = ctx.roleMapper;\n this.repository = ctx.repository;\n this.userRepository = ctx.userRepository;\n\n this.userValidator = new UserValidator();\n }\n\n async save(identity: IdentityProviderIdentity): Promise<IdentityProviderAccount> {\n let account = await this.repository.findOneByProviderIdentity(identity);\n if (account) {\n identity.operation = IdentityProviderIdentityOperation.UPDATE;\n\n account.user = await this.saveUser(identity, account.user);\n\n await this.repository.save(account);\n\n await this.saveRoles(identity, account.user);\n await this.savePermissions(identity, account.user);\n\n return account;\n }\n\n identity.operation = IdentityProviderIdentityOperation.CREATE;\n\n const user = await this.saveUser(identity);\n\n account = await this.repository.save({\n providerId: identity.provider.id,\n providerUserId: identity.id,\n providerUserName: user.name, // todo: parse identity.name\n providerRealmId: identity.provider.realmId,\n user,\n userId: user.id,\n userRealmId: user.realmId,\n });\n\n await this.saveRoles(identity, account.user);\n await this.savePermissions(identity, account.user);\n\n return account;\n }\n\n async saveUser(\n identity: IdentityProviderIdentity,\n user?: User,\n ): Promise<User> {\n const attributes = await this.attributesMapper.execute(\n identity,\n );\n\n const entity : Record<string, any> = {};\n for (const attribute of attributes) {\n if (\n attribute.key &&\n attribute.operation === IdentityProviderMapperOperation.CREATE\n ) {\n // attribute value might be object, array, ...\n entity[attribute.key] = attribute.value;\n }\n }\n\n if (!user) {\n entity.realmId = identity.provider.realmId;\n entity.active = true;\n entity.nameLocked = true;\n entity.clientId = identity.clientId || null;\n }\n\n const attributesSelf = await this.validateAttributes(entity, identity, 10);\n if (!attributesSelf) {\n // todo: better error name\n throw new Error('Identity provider attributes could not be validated.');\n }\n const attributesSelfKeys = Object.keys(attributesSelf);\n\n const attributesExtra : Record<string, any> = {};\n\n const entityKeys = Object.keys(entity);\n for (const entityKey of entityKeys) {\n const index = attributesSelfKeys.indexOf(entityKey);\n if (index !== -1) {\n continue;\n }\n\n attributesExtra[entityKey] = entity[entityKey];\n }\n\n let output : User;\n if (user) {\n output = extendObject(user, attributesSelf);\n } else {\n output = attributesSelf;\n }\n\n if (typeof output.name === 'string') {\n output.name = output.name.trim().toLowerCase();\n }\n\n let attempts = Math.max((identity.attributeCandidates?.name?.length || 0) + 1, 10);\n while (attempts > 0) {\n try {\n // todo: we also need to remove existing ones via idp login flow ( but not other attributes!)\n return await this.userRepository.saveOneWithEA(output, attributesExtra);\n } catch {\n const names = identity.attributeCandidates?.name || [];\n if (names.length > 0) {\n while (names.length > 0) {\n output.name = `${names.shift()}`.trim().toLowerCase();\n\n try {\n await this.userValidator.run(output, {\n group: identity.operation === IdentityProviderIdentityOperation.CREATE ?\n ValidatorGroup.CREATE :\n ValidatorGroup.UPDATE,\n });\n break;\n } catch {\n // todo: do nothing.\n }\n }\n } else {\n output.name = createNanoID('0123456789abcdefghijklmnopqrstuvwxyz-_', 10);\n }\n\n if (isUserFakeEmail(output.email)) {\n output.email = buildUserFakeEmail(output.name);\n }\n\n attempts -= 1;\n }\n }\n\n throw new Error('The user account could not be created due a conflict error.');\n }\n\n async validateAttributes(\n entity: Record<string, any>,\n identity: IdentityProviderIdentity,\n attempts: number,\n ) : Promise<User | null> {\n attempts--;\n if (attempts <= 0) {\n return null;\n }\n\n try {\n return await this.userValidator.run(entity, {\n group: identity.operation === IdentityProviderIdentityOperation.CREATE ?\n ValidatorGroup.CREATE :\n ValidatorGroup.UPDATE,\n });\n } catch (e: any) {\n if (!isValidupError(e)) {\n return null;\n }\n\n let retry = false;\n for (let i = 0; i < e.issues.length; i++) {\n const child = e.issues[i];\n\n const pathNormalized = stringifyPath(child.path);\n\n if (\n Array.isArray(entity[pathNormalized]) &&\n entity[pathNormalized].length > 0\n ) {\n const [first, ...rest] = entity[pathNormalized];\n entity[pathNormalized] = first;\n\n if (rest.length > 0) {\n if (!identity.attributeCandidates) {\n identity.attributeCandidates = {};\n }\n\n if (!identity.attributeCandidates[pathNormalized]) {\n identity.attributeCandidates[pathNormalized] = [];\n }\n\n identity.attributeCandidates[pathNormalized]!.push(...rest);\n }\n\n retry = true;\n break;\n }\n\n if (\n identity.attributeCandidates &&\n identity.attributeCandidates[pathNormalized] &&\n identity.attributeCandidates[pathNormalized]!.length > 0\n ) {\n entity[pathNormalized] = identity.attributeCandidates[pathNormalized]!.shift();\n retry = true;\n break;\n }\n\n if (\n entity.name &&\n pathNormalized === 'email'\n ) {\n entity[pathNormalized] = buildUserFakeEmail(entity.name);\n retry = true;\n break;\n }\n\n if (entity[pathNormalized]) {\n entity[pathNormalized] = null;\n break;\n }\n }\n\n if (retry) {\n return this.validateAttributes(entity, identity, attempts);\n }\n\n return null;\n }\n }\n\n async savePermissions(\n identity: IdentityProviderIdentity,\n user: User,\n ) {\n const entities = await this.permissionMapper.execute(identity);\n\n await this.userRepository.savePermissions(user, entities);\n }\n\n async saveRoles(\n identity: IdentityProviderIdentity,\n user: User,\n ) {\n const entities = await this.roleMapper.execute(identity);\n\n await this.userRepository.saveRoles(user, entities);\n }\n}\n"],"mappings":";;;;;;;;;;AAsBA,IAAaU,iCAAb,MAAaA;CACCC;CAEAC;CAEAC;CAEAC;CAEAC;CAEAC;CAEV,YAAYC,KAA4C;EACpD,KAAKN,mBAAmBM,IAAIC;EAC5B,KAAKN,mBAAmBK,IAAIL;EAC5B,KAAKC,aAAaI,IAAIJ;EACtB,KAAKC,aAAaG,IAAIH;EACtB,KAAKC,iBAAiBE,IAAIF;EAE1B,KAAKC,gBAAgB,IAAIhB,cAAAA;CAC7B;CAEA,MAAMmB,KAAKC,UAAsE;EAC7E,IAAIC,UAAU,MAAM,KAAKP,WAAWQ,0BAA0BF,QAAAA;EAC9D,IAAIC,SAAS;GACTD,SAASG,YAAYf,kCAAkCgB;GAEvDH,QAAQI,OAAO,MAAM,KAAKC,SAASN,UAAUC,QAAQI,IAAI;GAEzD,MAAM,KAAKX,WAAWK,KAAKE,OAAAA;GAE3B,MAAM,KAAKM,UAAUP,UAAUC,QAAQI,IAAI;GAC3C,MAAM,KAAKG,gBAAgBR,UAAUC,QAAQI,IAAI;GAEjD,OAAOJ;EACX;EAEAD,SAASG,YAAYf,kCAAkCqB;EAEvD,MAAMJ,OAAO,MAAM,KAAKC,SAASN,QAAAA;EAEjCC,UAAU,MAAM,KAAKP,WAAWK,KAAK;GACjCW,YAAYV,SAASW,SAASC;GAC9BC,gBAAgBb,SAASY;GACzBE,kBAAkBT,KAAKU;GACvBC,iBAAiBhB,SAASW,SAASM;GACnCZ;GACAa,QAAQb,KAAKO;GACbO,aAAad,KAAKY;EACtB,CAAA;EAEA,MAAM,KAAKV,UAAUP,UAAUC,QAAQI,IAAI;EAC3C,MAAM,KAAKG,gBAAgBR,UAAUC,QAAQI,IAAI;EAEjD,OAAOJ;CACX;CAEA,MAAMK,SACFN,UACAK,MACa;EACb,MAAMe,aAAa,MAAM,KAAK7B,iBAAiB8B,QAC3CrB,QAAAA;EAGJ,MAAMsB,SAA+B,CAAC;EACtC,KAAK,MAAMC,aAAaH,YACpB,IACIG,UAAUC,OACVD,UAAUpB,cAAcd,gCAAgCoB,QAGxDa,OAAOC,UAAUC,OAAOD,UAAUE;EAI1C,IAAI,CAACpB,MAAM;GACPiB,OAAOL,UAAUjB,SAASW,SAASM;GACnCK,OAAOI,SAAS;GAChBJ,OAAOK,aAAa;GACpBL,OAAOM,WAAW5B,SAAS4B,YAAY;EAC3C;EAEA,MAAMC,iBAAiB,MAAM,KAAKC,mBAAmBR,QAAQtB,UAAU,EAAA;EACvE,IAAI,CAAC6B,gBAED,MAAM,IAAIE,MAAM,sDAAA;EAEpB,MAAMC,qBAAqBC,OAAOC,KAAKL,cAAAA;EAEvC,MAAMM,kBAAwC,CAAC;EAE/C,MAAMC,aAAaH,OAAOC,KAAKZ,MAAAA;EAC/B,KAAK,MAAMe,aAAaD,YAAY;GAEhC,IADcJ,mBAAmBO,QAAQF,SACrCC,MAAU,IACV;GAGJH,gBAAgBE,aAAaf,OAAOe;EACxC;EAEA,IAAIG;EACJ,IAAInC,MACAmC,SAASvD,aAAaoB,MAAMwB,cAAAA;OAE5BW,SAASX;EAGb,IAAI,OAAOW,OAAOzB,SAAS,UACvByB,OAAOzB,OAAOyB,OAAOzB,KAAK0B,KAAI,CAAA,CAAGC,YAAW;EAGhD,IAAIC,WAAWC,KAAKC,KAAK7C,SAAS8C,qBAAqB/B,MAAMgC,UAAU,KAAK,GAAG,EAAA;EAC/E,OAAOJ,WAAW,GACd,IAAI;GAEA,OAAO,MAAM,KAAKhD,eAAeqD,cAAcR,QAAQL,eAAAA;EAC3D,QAAQ;GACJ,MAAMc,QAAQjD,SAAS8C,qBAAqB/B,QAAQ,CAAA;GACpD,IAAIkC,MAAMF,SAAS,GACf,OAAOE,MAAMF,SAAS,GAAG;IACrBP,OAAOzB,OAAO,GAAGkC,MAAMC,MAAK,IAAKT,KAAI,CAAA,CAAGC,YAAW;IAEnD,IAAI;KACA,MAAM,KAAK9C,cAAcuD,IAAIX,QAAQ,EACjCY,OAAOpD,SAASG,cAAcf,kCAAkCqB,SAC5D1B,eAAe0B,SACf1B,eAAeqB,OACvB,CAAA;KACA;IACJ,QAAQ,CAER;GACJ;QAEAoC,OAAOzB,OAAO/B,aAAa,0CAA0C,EAAA;GAGzE,IAAIF,gBAAgB0D,OAAOa,KAAK,GAC5Bb,OAAOa,QAAQxE,mBAAmB2D,OAAOzB,IAAI;GAGjD4B,YAAY;EAChB;EAGJ,MAAM,IAAIZ,MAAM,6DAAA;CACpB;CAEA,MAAMD,mBACFR,QACAtB,UACA2C,UACqB;EACrBA;EACA,IAAIA,YAAY,GACZ,OAAO;EAGX,IAAI;GACA,OAAO,MAAM,KAAK/C,cAAcuD,IAAI7B,QAAQ,EACxC8B,OAAOpD,SAASG,cAAcf,kCAAkCqB,SAC5D1B,eAAe0B,SACf1B,eAAeqB,OACvB,CAAA;EACJ,SAASkD,GAAQ;GACb,IAAI,CAACpE,eAAeoE,CAAAA,GAChB,OAAO;GAGX,IAAIC,QAAQ;GACZ,KAAK,IAAIC,IAAI,GAAGA,IAAIF,EAAEG,OAAOV,QAAQS,KAAK;IACtC,MAAME,QAAQJ,EAAEG,OAAOD;IAEvB,MAAMG,iBAAiBxE,cAAcuE,MAAME,IAAI;IAE/C,IACIC,MAAMC,QAAQxC,OAAOqC,eAAe,KACpCrC,OAAOqC,eAAe,CAACZ,SAAS,GAClC;KACE,MAAM,CAACgB,OAAO,GAAGC,QAAQ1C,OAAOqC;KAChCrC,OAAOqC,kBAAkBI;KAEzB,IAAIC,KAAKjB,SAAS,GAAG;MACjB,IAAI,CAAC/C,SAAS8C,qBACV9C,SAAS8C,sBAAsB,CAAC;MAGpC,IAAI,CAAC9C,SAAS8C,oBAAoBa,iBAC9B3D,SAAS8C,oBAAoBa,kBAAkB,CAAA;MAGnD3D,SAAS8C,oBAAoBa,eAAe,CAAEM,KAAI,GAAID,IAAAA;KAC1D;KAEAT,QAAQ;KACR;IACJ;IAEA,IACIvD,SAAS8C,uBACT9C,SAAS8C,oBAAoBa,mBAC7B3D,SAAS8C,oBAAoBa,eAAe,CAAEZ,SAAS,GACzD;KACEzB,OAAOqC,kBAAkB3D,SAAS8C,oBAAoBa,eAAe,CAAET,MAAK;KAC5EK,QAAQ;KACR;IACJ;IAEA,IACIjC,OAAOP,QACP4C,mBAAmB,SACrB;KACErC,OAAOqC,kBAAkB9E,mBAAmByC,OAAOP,IAAI;KACvDwC,QAAQ;KACR;IACJ;IAEA,IAAIjC,OAAOqC,iBAAiB;KACxBrC,OAAOqC,kBAAkB;KACzB;IACJ;GACJ;GAEA,IAAIJ,OACA,OAAO,KAAKzB,mBAAmBR,QAAQtB,UAAU2C,QAAAA;GAGrD,OAAO;EACX;CACJ;CAEA,MAAMnC,gBACFR,UACAK,MACF;EACE,MAAM6D,WAAW,MAAM,KAAK1E,iBAAiB6B,QAAQrB,QAAAA;EAErD,MAAM,KAAKL,eAAea,gBAAgBH,MAAM6D,QAAAA;CACpD;CAEA,MAAM3D,UACFP,UACAK,MACF;EACE,MAAM6D,WAAW,MAAM,KAAKzE,WAAW4B,QAAQrB,QAAAA;EAE/C,MAAM,KAAKL,eAAeY,UAAUF,MAAM6D,QAAAA;CAC9C;AACJ"}
|
|
1
|
+
{"version":3,"file":"module.mjs","names":["UserValidator","buildUserFakeEmail","isUserFakeEmail","ValidatorGroup","createNanoID","extendObject","ValidationError","isValidupError","stringifyPath","IdentityProviderIdentityOperation","IdentityProviderMapperOperation","IdentityProviderAccountAlreadyLinkedError","IdentityProviderAccountManager","attributesMapper","permissionMapper","roleMapper","repository","userRepository","userValidator","ctx","attributeMapper","save","identity","account","findOneByProviderIdentity","operation","UPDATE","user","saveUser","saveRoles","savePermissions","CREATE","providerId","provider","id","providerUserId","providerUserName","name","providerRealmId","realmId","userId","userRealmId","link","findOneById","pickCandidate","slice","providerUserEmail","existing","undefined","key","maxLength","candidates","attributeCandidates","candidate","length","attributes","execute","entity","attribute","value","active","nameLocked","clientId","attributesSelf","validateAttributes","Error","attributesSelfKeys","Object","keys","attributesExtra","entityKeys","entityKey","index","indexOf","output","trim","toLowerCase","attempts","Math","max","saveOneWithEA","names","shift","run","group","email","e","retry","i","issues","child","pathNormalized","path","Array","isArray","first","rest","push","entities"],"sources":["../../../../../src/core/identity/provider/account/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 { IdentityProviderAccount, User } from '@authup/core-kit';\nimport {\n UserValidator,\n buildUserFakeEmail,\n isUserFakeEmail,\n} from '@authup/core-kit';\nimport { ValidatorGroup, createNanoID, extendObject } from '@authup/kit';\nimport { ValidationError } from '@authup/errors';\nimport { isValidupError, stringifyPath } from 'validup';\nimport type { IUserIdentityRepository } from '../../entities/index.ts';\nimport { IdentityProviderIdentityOperation } from '../constants.ts';\nimport type { IIdentityProviderMapper } from '../mapper/index.ts';\nimport { IdentityProviderMapperOperation } from '../mapper/index.ts';\nimport type { IdentityProviderIdentity } from '../types.ts';\nimport { IdentityProviderAccountAlreadyLinkedError } from './error.ts';\nimport type { IIdentityProviderAccountManager, IIdentityProviderAccountRepository, IdentityProviderAccountManagerContext } from './types.ts';\n\nexport class IdentityProviderAccountManager implements IIdentityProviderAccountManager {\n protected attributesMapper : IIdentityProviderMapper;\n\n protected permissionMapper : IIdentityProviderMapper;\n\n protected roleMapper : IIdentityProviderMapper;\n\n protected repository : IIdentityProviderAccountRepository;\n\n protected userRepository: IUserIdentityRepository;\n\n protected userValidator : UserValidator;\n\n constructor(ctx: IdentityProviderAccountManagerContext) {\n this.attributesMapper = ctx.attributeMapper;\n this.permissionMapper = ctx.permissionMapper;\n this.roleMapper = ctx.roleMapper;\n this.repository = ctx.repository;\n this.userRepository = ctx.userRepository;\n\n this.userValidator = new UserValidator();\n }\n\n async save(identity: IdentityProviderIdentity): Promise<IdentityProviderAccount> {\n let account = await this.repository.findOneByProviderIdentity(identity);\n if (account) {\n identity.operation = IdentityProviderIdentityOperation.UPDATE;\n\n account.user = await this.saveUser(identity, account.user);\n\n await this.repository.save(account);\n\n await this.saveRoles(identity, account.user);\n await this.savePermissions(identity, account.user);\n\n return account;\n }\n\n identity.operation = IdentityProviderIdentityOperation.CREATE;\n\n const user = await this.saveUser(identity);\n\n account = await this.repository.save({\n providerId: identity.provider.id,\n providerUserId: identity.id,\n providerUserName: user.name, // todo: parse identity.name\n providerRealmId: identity.provider.realmId,\n user,\n userId: user.id,\n userRealmId: user.realmId,\n });\n\n await this.saveRoles(identity, account.user);\n await this.savePermissions(identity, account.user);\n\n return account;\n }\n\n async link(identity: IdentityProviderIdentity, userId: string): Promise<IdentityProviderAccount> {\n const user = await this.userRepository.findOneById(userId);\n if (!user) {\n throw new ValidationError('The linking user does not exist.');\n }\n\n if (\n identity.provider.realmId &&\n user.realmId !== identity.provider.realmId\n ) {\n throw new ValidationError('The provider and user realm do not match.');\n }\n\n const providerUserName = this.pickCandidate(identity, 'name', 256) ?? identity.id.slice(0, 256);\n const providerUserEmail = this.pickCandidate(identity, 'email', 512);\n\n const existing = await this.repository.findOneByProviderIdentity(identity);\n if (existing) {\n if (existing.userId !== userId) {\n throw new IdentityProviderAccountAlreadyLinkedError();\n }\n\n existing.providerUserName = providerUserName ?? existing.providerUserName;\n existing.providerUserEmail = providerUserEmail ?? existing.providerUserEmail;\n\n return this.repository.save(existing);\n }\n\n return this.repository.save({\n providerId: identity.provider.id,\n providerUserId: identity.id,\n providerUserName,\n providerUserEmail: providerUserEmail ?? undefined,\n providerRealmId: identity.provider.realmId,\n userId,\n userRealmId: user.realmId ?? null,\n });\n }\n\n protected pickCandidate(\n identity: IdentityProviderIdentity,\n key: keyof User,\n maxLength: number,\n ): string | null {\n const candidates = identity.attributeCandidates?.[key] || [];\n for (const candidate of candidates) {\n if (typeof candidate === 'string' && candidate.length > 0) {\n return candidate.slice(0, maxLength);\n }\n }\n\n return null;\n }\n\n async saveUser(\n identity: IdentityProviderIdentity,\n user?: User,\n ): Promise<User> {\n const attributes = await this.attributesMapper.execute(\n identity,\n );\n\n const entity : Record<string, any> = {};\n for (const attribute of attributes) {\n if (\n attribute.key &&\n attribute.operation === IdentityProviderMapperOperation.CREATE\n ) {\n // attribute value might be object, array, ...\n entity[attribute.key] = attribute.value;\n }\n }\n\n if (!user) {\n entity.realmId = identity.provider.realmId;\n entity.active = true;\n entity.nameLocked = true;\n entity.clientId = identity.clientId || null;\n }\n\n const attributesSelf = await this.validateAttributes(entity, identity, 10);\n if (!attributesSelf) {\n // todo: better error name\n throw new Error('Identity provider attributes could not be validated.');\n }\n const attributesSelfKeys = Object.keys(attributesSelf);\n\n const attributesExtra : Record<string, any> = {};\n\n const entityKeys = Object.keys(entity);\n for (const entityKey of entityKeys) {\n const index = attributesSelfKeys.indexOf(entityKey);\n if (index !== -1) {\n continue;\n }\n\n attributesExtra[entityKey] = entity[entityKey];\n }\n\n let output : User;\n if (user) {\n output = extendObject(user, attributesSelf);\n } else {\n output = attributesSelf;\n }\n\n if (typeof output.name === 'string') {\n output.name = output.name.trim().toLowerCase();\n }\n\n let attempts = Math.max((identity.attributeCandidates?.name?.length || 0) + 1, 10);\n while (attempts > 0) {\n try {\n // todo: we also need to remove existing ones via idp login flow ( but not other attributes!)\n return await this.userRepository.saveOneWithEA(output, attributesExtra);\n } catch {\n const names = identity.attributeCandidates?.name || [];\n if (names.length > 0) {\n while (names.length > 0) {\n output.name = `${names.shift()}`.trim().toLowerCase();\n\n try {\n await this.userValidator.run(output, {\n group: identity.operation === IdentityProviderIdentityOperation.CREATE ?\n ValidatorGroup.CREATE :\n ValidatorGroup.UPDATE,\n });\n break;\n } catch {\n // todo: do nothing.\n }\n }\n } else {\n output.name = createNanoID('0123456789abcdefghijklmnopqrstuvwxyz-_', 10);\n }\n\n if (isUserFakeEmail(output.email)) {\n output.email = buildUserFakeEmail(output.name);\n }\n\n attempts -= 1;\n }\n }\n\n throw new Error('The user account could not be created due a conflict error.');\n }\n\n async validateAttributes(\n entity: Record<string, any>,\n identity: IdentityProviderIdentity,\n attempts: number,\n ) : Promise<User | null> {\n attempts--;\n if (attempts <= 0) {\n return null;\n }\n\n try {\n return await this.userValidator.run(entity, {\n group: identity.operation === IdentityProviderIdentityOperation.CREATE ?\n ValidatorGroup.CREATE :\n ValidatorGroup.UPDATE,\n });\n } catch (e: any) {\n if (!isValidupError(e)) {\n return null;\n }\n\n let retry = false;\n for (let i = 0; i < e.issues.length; i++) {\n const child = e.issues[i];\n\n const pathNormalized = stringifyPath(child.path);\n\n if (\n Array.isArray(entity[pathNormalized]) &&\n entity[pathNormalized].length > 0\n ) {\n const [first, ...rest] = entity[pathNormalized];\n entity[pathNormalized] = first;\n\n if (rest.length > 0) {\n if (!identity.attributeCandidates) {\n identity.attributeCandidates = {};\n }\n\n if (!identity.attributeCandidates[pathNormalized]) {\n identity.attributeCandidates[pathNormalized] = [];\n }\n\n identity.attributeCandidates[pathNormalized]!.push(...rest);\n }\n\n retry = true;\n break;\n }\n\n if (\n identity.attributeCandidates &&\n identity.attributeCandidates[pathNormalized] &&\n identity.attributeCandidates[pathNormalized]!.length > 0\n ) {\n entity[pathNormalized] = identity.attributeCandidates[pathNormalized]!.shift();\n retry = true;\n break;\n }\n\n if (\n entity.name &&\n pathNormalized === 'email'\n ) {\n entity[pathNormalized] = buildUserFakeEmail(entity.name);\n retry = true;\n break;\n }\n\n if (entity[pathNormalized]) {\n entity[pathNormalized] = null;\n break;\n }\n }\n\n if (retry) {\n return this.validateAttributes(entity, identity, attempts);\n }\n\n return null;\n }\n }\n\n async savePermissions(\n identity: IdentityProviderIdentity,\n user: User,\n ) {\n const entities = await this.permissionMapper.execute(identity);\n\n await this.userRepository.savePermissions(user, entities);\n }\n\n async saveRoles(\n identity: IdentityProviderIdentity,\n user: User,\n ) {\n const entities = await this.roleMapper.execute(identity);\n\n await this.userRepository.saveRoles(user, entities);\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,16 +1,43 @@
|
|
|
1
1
|
import type { IdentityProviderAccount } from '@authup/core-kit';
|
|
2
|
-
import type { DeepPartial } from 'typeorm';
|
|
3
2
|
import type { IUserIdentityRepository } from '../../entities/index.ts';
|
|
4
3
|
import type { IIdentityProviderMapper } from '../mapper/index.ts';
|
|
5
4
|
import type { IdentityProviderIdentity } from '../types.ts';
|
|
6
|
-
|
|
5
|
+
import type { IIdentityProviderAccountRepository } from '../../../entities/identity-provider-account/types.ts';
|
|
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;
|
|
7
20
|
/**
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
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
|
|
11
34
|
*/
|
|
12
|
-
|
|
13
|
-
|
|
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>;
|
|
14
41
|
}
|
|
15
42
|
export type IdentityProviderAccountManagerContext = {
|
|
16
43
|
attributeMapper: IIdentityProviderMapper;
|
|
@@ -26,5 +53,15 @@ export interface IIdentityProviderAccountManager {
|
|
|
26
53
|
* @param identity
|
|
27
54
|
*/
|
|
28
55
|
save(identity: IdentityProviderIdentity): Promise<IdentityProviderAccount>;
|
|
56
|
+
/**
|
|
57
|
+
* Explicitly link the external identity to an EXISTING user (plan
|
|
58
|
+
* 091): creates or refreshes the account row only. Never mutates the
|
|
59
|
+
* user, never runs attribute/role/permission mappers, never creates
|
|
60
|
+
* a user.
|
|
61
|
+
*
|
|
62
|
+
* @param identity
|
|
63
|
+
* @param userId
|
|
64
|
+
*/
|
|
65
|
+
link(identity: IdentityProviderIdentity, userId: string): Promise<IdentityProviderAccount>;
|
|
29
66
|
}
|
|
30
67
|
//# sourceMappingURL=types.d.ts.map
|
|
@@ -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,
|
|
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,10 +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;
|
|
18
|
+
resolveIdentity(params: OAuth2AuthorizationCodeGrantPayload): Promise<IdentityProviderIdentity>;
|
|
15
19
|
authenticate(params: OAuth2AuthorizationCodeGrantPayload): Promise<User>;
|
|
16
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>;
|
|
17
36
|
protected buildIdentityWithTokenGrantResponse(input: TokenGrantResponse): Promise<IdentityProviderIdentity>;
|
|
18
37
|
}
|
|
19
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;
|
|
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,
|
|
@@ -32,10 +38,14 @@ var IdentityProviderOAuth2Authenticator = class {
|
|
|
32
38
|
throw new ValidationError("The identity provider is misconfigured and has an invalid or missing authorize URL.");
|
|
33
39
|
}
|
|
34
40
|
}
|
|
35
|
-
async
|
|
41
|
+
async resolveIdentity(params) {
|
|
36
42
|
const token = await this.client.token.createWithAuthorizationCode(params);
|
|
37
43
|
const identity = await this.buildIdentityWithTokenGrantResponse(token);
|
|
38
44
|
if (this.options.clientId) identity.clientId = this.options.clientId;
|
|
45
|
+
return identity;
|
|
46
|
+
}
|
|
47
|
+
async authenticate(params) {
|
|
48
|
+
const identity = await this.resolveIdentity(params);
|
|
39
49
|
return (await this.accountManager.save(identity)).user;
|
|
40
50
|
}
|
|
41
51
|
async safeAuthenticate(params) {
|
|
@@ -51,13 +61,60 @@ var IdentityProviderOAuth2Authenticator = class {
|
|
|
51
61
|
};
|
|
52
62
|
}
|
|
53
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
|
+
}
|
|
54
105
|
async buildIdentityWithTokenGrantResponse(input) {
|
|
55
106
|
const payload = extractTokenPayload(input.access_token);
|
|
107
|
+
const claims = await this.resolveClaims(input, payload);
|
|
56
108
|
return {
|
|
57
109
|
id: payload.sub,
|
|
58
110
|
attributeCandidates: {
|
|
59
|
-
name: [
|
|
60
|
-
|
|
111
|
+
name: [
|
|
112
|
+
claims.preferred_username,
|
|
113
|
+
claims.nickname,
|
|
114
|
+
claims.name,
|
|
115
|
+
claims.sub
|
|
116
|
+
],
|
|
117
|
+
email: [claims.email]
|
|
61
118
|
},
|
|
62
119
|
data: payload,
|
|
63
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","authenticate","params","token","createWithAuthorizationCode","identity","buildIdentityWithTokenGrantResponse","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 authenticate(params: OAuth2AuthorizationCodeGrantPayload): Promise<User> {\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 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,aAAaC,QAA4D;EAC3E,MAAMC,QAAQ,MAAM,KAAKxB,OAAOwB,MAAMC,4BAA4BF,MAAAA;EAElE,MAAMG,WAAW,MAAM,KAAKC,oCAAoCH,KAAAA;EAChE,IAAI,KAAKvB,QAAQI,UACbqB,SAASrB,WAAW,KAAKJ,QAAQI;EAKrC,QAAOuB,MAFe,KAAK1B,eAAe2B,KAAKH,QAAAA,EAAAA,CAEhCI;CACnB;CAEA,MAAMC,iBAAiBR,QAAoE;EACvF,IAAI;GAEA,OAAO;IACHU,SAAS;IACTD,MAAAA,MAHe,KAAKV,aAAaC,MAAAA;GAIrC;EACJ,SAASW,GAAG;GACR,OAAO;IACHD,SAAS;IACTE,OAAOD;GACX;EACJ;CACJ;CAIA,MAAgBP,oCAAoCS,OAA+D;EAC/G,MAAMC,UAAUxC,oBAAoBuC,MAAME,YAAY;EAEtD,OAAO;GACH7B,IAAI4B,QAAQE;GACZC,qBAAqB;IACjBC,MAAM,CACFJ,QAAQE,GACX;IACDG,OAAO,CACHL,QAAQK,KACX;GACL;GACAV,MAAMK;GACNlC,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,7 +1,9 @@
|
|
|
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';
|
|
6
|
+
import type { IdentityProviderIdentity } from '../../../types.ts';
|
|
5
7
|
export type OAuth2AuthorizationCodeGrantPayload = {
|
|
6
8
|
code: string;
|
|
7
9
|
code_verifier?: string;
|
|
@@ -9,6 +11,12 @@ export type OAuth2AuthorizationCodeGrantPayload = {
|
|
|
9
11
|
export interface IOAuth2Authenticator<T extends ObjectLiteral = ObjectLiteral> {
|
|
10
12
|
authenticate(params: OAuth2AuthorizationCodeGrantPayload): Promise<T>;
|
|
11
13
|
safeAuthenticate(params: OAuth2AuthorizationCodeGrantPayload): Promise<Result<T>>;
|
|
14
|
+
/**
|
|
15
|
+
* Exchange the code and build the external identity WITHOUT touching
|
|
16
|
+
* the account store. The account-linking path decides what to do
|
|
17
|
+
* with the identity.
|
|
18
|
+
*/
|
|
19
|
+
resolveIdentity(params: OAuth2AuthorizationCodeGrantPayload): Promise<IdentityProviderIdentity>;
|
|
12
20
|
buildRedirectURL(parameters?: Partial<AuthorizeParameters>): string;
|
|
13
21
|
}
|
|
14
22
|
export type IdentityProviderOAuth2AuthenticatorOptions = {
|
|
@@ -19,5 +27,6 @@ export type IdentityProviderOAuth2AuthenticatorContext = {
|
|
|
19
27
|
options: IdentityProviderOAuth2AuthenticatorOptions;
|
|
20
28
|
accountManager: IIdentityProviderAccountManager;
|
|
21
29
|
provider: OAuth2IdentityProvider | OpenIDIdentityProvider;
|
|
30
|
+
logger?: Logger;
|
|
22
31
|
};
|
|
23
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;
|
|
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"}
|