@authup/server-core 1.0.0-beta.62 → 1.0.0-beta.64
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/data-source/options/module.d.ts +1 -0
- package/dist/adapters/database/data-source/options/module.d.ts.map +1 -1
- package/dist/adapters/database/data-source/options/module.mjs +33 -4
- package/dist/adapters/database/data-source/options/module.mjs.map +1 -1
- package/dist/adapters/database/domains/client/entity.d.ts +1 -2
- package/dist/adapters/database/domains/client/entity.d.ts.map +1 -1
- package/dist/adapters/database/domains/client/entity.mjs +7 -14
- package/dist/adapters/database/domains/client/entity.mjs.map +1 -1
- package/dist/adapters/database/domains/identity-provider-attribute/subscriber.d.ts +9 -1
- package/dist/adapters/database/domains/identity-provider-attribute/subscriber.d.ts.map +1 -1
- package/dist/adapters/database/domains/identity-provider-attribute/subscriber.mjs +14 -0
- package/dist/adapters/database/domains/identity-provider-attribute/subscriber.mjs.map +1 -1
- package/dist/adapters/database/domains/session/entity.d.ts +8 -0
- package/dist/adapters/database/domains/session/entity.d.ts.map +1 -1
- package/dist/adapters/database/domains/session/entity.mjs +19 -0
- package/dist/adapters/database/domains/session/entity.mjs.map +1 -1
- package/dist/adapters/database/domains/user/entity.d.ts +1 -0
- package/dist/adapters/database/domains/user/entity.d.ts.map +1 -1
- package/dist/adapters/database/domains/user/entity.mjs +6 -0
- package/dist/adapters/database/domains/user/entity.mjs.map +1 -1
- package/dist/adapters/database/extra-attribute-repository/repository.mjs +1 -1
- package/dist/adapters/database/extra-attribute-repository/repository.mjs.map +1 -1
- package/dist/adapters/database/extra-attribute-repository/tree/adapter.mjs +4 -2
- package/dist/adapters/database/extra-attribute-repository/tree/adapter.mjs.map +1 -1
- package/dist/adapters/database/extra-attribute-repository/tree/repository.mjs +1 -1
- package/dist/adapters/database/extra-attribute-repository/tree/repository.mjs.map +1 -1
- package/dist/adapters/database/index.mjs +3 -3
- package/dist/adapters/database/migrations/mysql/1787571998009-SessionUserAndClientColumns.d.ts +56 -0
- package/dist/adapters/database/migrations/mysql/1787571998009-SessionUserAndClientColumns.d.ts.map +1 -0
- package/dist/adapters/database/migrations/mysql/1787571998009-SessionUserAndClientColumns.mjs +105 -0
- package/dist/adapters/database/migrations/mysql/1787571998009-SessionUserAndClientColumns.mjs.map +1 -0
- package/dist/adapters/database/migrations/postgres/1787571998009-SessionUserAndClientColumns.d.ts +56 -0
- package/dist/adapters/database/migrations/postgres/1787571998009-SessionUserAndClientColumns.d.ts.map +1 -0
- package/dist/adapters/database/migrations/postgres/1787571998009-SessionUserAndClientColumns.mjs +104 -0
- package/dist/adapters/database/migrations/postgres/1787571998009-SessionUserAndClientColumns.mjs.map +1 -0
- package/dist/adapters/database/subscriber/module.d.ts +6 -2
- package/dist/adapters/database/subscriber/module.d.ts.map +1 -1
- package/dist/adapters/database/subscriber/module.mjs +9 -5
- package/dist/adapters/database/subscriber/module.mjs.map +1 -1
- package/dist/adapters/http/adapters/oauth2/authorization/module.mjs +1 -1
- package/dist/adapters/http/adapters/oauth2/authorization/module.mjs.map +1 -1
- package/dist/adapters/http/adapters/oauth2/grant-types/refresh_token.d.ts.map +1 -1
- package/dist/adapters/http/adapters/oauth2/grant-types/refresh_token.mjs +8 -2
- package/dist/adapters/http/adapters/oauth2/grant-types/refresh_token.mjs.map +1 -1
- package/dist/adapters/http/constants.d.ts +18 -0
- package/dist/adapters/http/constants.d.ts.map +1 -0
- package/dist/adapters/http/constants.mjs +23 -0
- package/dist/adapters/http/constants.mjs.map +1 -0
- package/dist/adapters/http/controllers/entities/client/module.mjs +1 -1
- package/dist/adapters/http/controllers/entities/identity-provider/module.d.ts +23 -1
- package/dist/adapters/http/controllers/entities/identity-provider/module.d.ts.map +1 -1
- package/dist/adapters/http/controllers/entities/identity-provider/module.mjs +86 -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 +6 -0
- package/dist/adapters/http/controllers/entities/identity-provider/types.d.ts.map +1 -1
- package/dist/adapters/http/controllers/entities/realm/module.d.ts.map +1 -1
- package/dist/adapters/http/controllers/entities/realm/module.mjs +2 -0
- package/dist/adapters/http/controllers/entities/realm/module.mjs.map +1 -1
- package/dist/adapters/http/controllers/entities/session/module.d.ts +33 -1
- package/dist/adapters/http/controllers/entities/session/module.d.ts.map +1 -1
- package/dist/adapters/http/controllers/entities/session/module.mjs +74 -0
- package/dist/adapters/http/controllers/entities/session/module.mjs.map +1 -1
- package/dist/adapters/http/controllers/index.mjs +3 -1
- package/dist/adapters/http/controllers/workflows/account/index.d.ts +1 -0
- package/dist/adapters/http/controllers/workflows/account/index.d.ts.map +1 -1
- package/dist/adapters/http/controllers/workflows/account/module.d.ts +25 -16
- package/dist/adapters/http/controllers/workflows/account/module.d.ts.map +1 -1
- package/dist/adapters/http/controllers/workflows/account/module.mjs +40 -17
- package/dist/adapters/http/controllers/workflows/account/module.mjs.map +1 -1
- package/dist/adapters/http/controllers/workflows/account/types.d.ts +33 -0
- package/dist/adapters/http/controllers/workflows/account/types.d.ts.map +1 -0
- package/dist/adapters/http/controllers/workflows/activate/module.d.ts +8 -4
- package/dist/adapters/http/controllers/workflows/activate/module.d.ts.map +1 -1
- package/dist/adapters/http/controllers/workflows/activate/module.mjs +7 -9
- package/dist/adapters/http/controllers/workflows/activate/module.mjs.map +1 -1
- package/dist/adapters/http/controllers/workflows/admin/index.d.ts.map +1 -0
- package/dist/adapters/http/controllers/workflows/admin/index.mjs +5 -0
- package/dist/adapters/http/controllers/workflows/admin/module.d.ts +30 -0
- package/dist/adapters/http/controllers/workflows/admin/module.d.ts.map +1 -0
- package/dist/adapters/http/controllers/workflows/admin/module.mjs +88 -0
- package/dist/adapters/http/controllers/workflows/admin/module.mjs.map +1 -0
- package/dist/adapters/http/controllers/workflows/admin/types.d.ts +14 -0
- package/dist/adapters/http/controllers/workflows/admin/types.d.ts.map +1 -0
- package/dist/adapters/http/controllers/workflows/auth-console.d.ts +16 -0
- package/dist/adapters/http/controllers/workflows/auth-console.d.ts.map +1 -0
- package/dist/adapters/http/controllers/workflows/auth-console.mjs +32 -0
- package/dist/adapters/http/controllers/workflows/auth-console.mjs.map +1 -0
- package/dist/adapters/http/controllers/workflows/authenticator-challenge/module.d.ts +2 -0
- package/dist/adapters/http/controllers/workflows/authenticator-challenge/module.d.ts.map +1 -1
- package/dist/adapters/http/controllers/workflows/authenticator-challenge/module.mjs +21 -3
- package/dist/adapters/http/controllers/workflows/authenticator-challenge/module.mjs.map +1 -1
- package/dist/adapters/http/controllers/workflows/authorize/module.d.ts +16 -1
- package/dist/adapters/http/controllers/workflows/authorize/module.d.ts.map +1 -1
- package/dist/adapters/http/controllers/workflows/authorize/module.mjs +44 -21
- package/dist/adapters/http/controllers/workflows/authorize/module.mjs.map +1 -1
- package/dist/adapters/http/controllers/workflows/authorize/types.d.ts +5 -0
- package/dist/adapters/http/controllers/workflows/authorize/types.d.ts.map +1 -1
- package/dist/adapters/http/controllers/workflows/console-login/index.d.ts +3 -0
- package/dist/adapters/http/controllers/workflows/console-login/index.d.ts.map +1 -0
- package/dist/adapters/http/controllers/workflows/console-login/index.mjs +5 -0
- package/dist/adapters/http/controllers/workflows/console-login/module.d.ts +83 -0
- package/dist/adapters/http/controllers/workflows/console-login/module.d.ts.map +1 -0
- package/dist/adapters/http/controllers/workflows/console-login/module.mjs +230 -0
- package/dist/adapters/http/controllers/workflows/console-login/module.mjs.map +1 -0
- package/dist/adapters/http/controllers/workflows/console-login/types.d.ts +58 -0
- package/dist/adapters/http/controllers/workflows/console-login/types.d.ts.map +1 -0
- package/dist/adapters/http/controllers/workflows/index.d.ts +2 -0
- package/dist/adapters/http/controllers/workflows/index.d.ts.map +1 -1
- package/dist/adapters/http/controllers/workflows/index.mjs +5 -1
- package/dist/adapters/http/controllers/workflows/logout/module.d.ts +32 -3
- package/dist/adapters/http/controllers/workflows/logout/module.d.ts.map +1 -1
- package/dist/adapters/http/controllers/workflows/logout/module.mjs +48 -24
- package/dist/adapters/http/controllers/workflows/logout/module.mjs.map +1 -1
- package/dist/adapters/http/controllers/workflows/logout/types.d.ts +1 -1
- package/dist/adapters/http/controllers/workflows/logout/types.d.ts.map +1 -1
- package/dist/adapters/http/controllers/workflows/password-forgot/module.d.ts +8 -4
- package/dist/adapters/http/controllers/workflows/password-forgot/module.d.ts.map +1 -1
- package/dist/adapters/http/controllers/workflows/password-forgot/module.mjs +7 -9
- package/dist/adapters/http/controllers/workflows/password-forgot/module.mjs.map +1 -1
- package/dist/adapters/http/controllers/workflows/password-reset/module.d.ts +8 -4
- package/dist/adapters/http/controllers/workflows/password-reset/module.d.ts.map +1 -1
- package/dist/adapters/http/controllers/workflows/password-reset/module.mjs +7 -10
- package/dist/adapters/http/controllers/workflows/password-reset/module.mjs.map +1 -1
- package/dist/adapters/http/controllers/workflows/register/module.d.ts +8 -4
- package/dist/adapters/http/controllers/workflows/register/module.d.ts.map +1 -1
- package/dist/adapters/http/controllers/workflows/register/module.mjs +7 -9
- package/dist/adapters/http/controllers/workflows/register/module.mjs.map +1 -1
- package/dist/adapters/http/controllers/workflows/status/module.mjs +1 -1
- package/dist/adapters/http/controllers/workflows/token/module.d.ts +45 -2
- package/dist/adapters/http/controllers/workflows/token/module.d.ts.map +1 -1
- package/dist/adapters/http/controllers/workflows/token/module.mjs +117 -26
- package/dist/adapters/http/controllers/workflows/token/module.mjs.map +1 -1
- package/dist/adapters/http/cookie/index.d.ts +2 -0
- package/dist/adapters/http/cookie/index.d.ts.map +1 -0
- package/dist/adapters/http/cookie/index.mjs +5 -0
- package/dist/adapters/http/cookie/session.d.ts +35 -0
- package/dist/adapters/http/cookie/session.d.ts.map +1 -0
- package/dist/adapters/http/cookie/session.mjs +62 -0
- package/dist/adapters/http/cookie/session.mjs.map +1 -0
- package/dist/adapters/http/index.d.ts +2 -0
- package/dist/adapters/http/index.d.ts.map +1 -1
- package/dist/adapters/http/index.mjs +20 -16
- package/dist/adapters/http/internal-client/index.d.ts +3 -0
- package/dist/adapters/http/internal-client/index.d.ts.map +1 -0
- package/dist/adapters/http/internal-client/index.mjs +5 -0
- package/dist/adapters/http/internal-client/module.d.ts +21 -0
- package/dist/adapters/http/internal-client/module.d.ts.map +1 -0
- package/dist/adapters/http/{ui/auth-console/http-client.mjs → internal-client/module.mjs} +16 -15
- package/dist/adapters/http/internal-client/module.mjs.map +1 -0
- package/dist/adapters/http/internal-client/types.d.ts +13 -0
- package/dist/adapters/http/internal-client/types.d.ts.map +1 -0
- package/dist/adapters/http/middleware/built-in/authorization/index.d.ts +1 -0
- package/dist/adapters/http/middleware/built-in/authorization/index.d.ts.map +1 -1
- package/dist/adapters/http/middleware/built-in/authorization/index.mjs +2 -1
- package/dist/adapters/http/middleware/built-in/authorization/issuance.d.ts +45 -0
- package/dist/adapters/http/middleware/built-in/authorization/issuance.d.ts.map +1 -0
- package/dist/adapters/http/middleware/built-in/authorization/issuance.mjs +61 -0
- package/dist/adapters/http/middleware/built-in/authorization/issuance.mjs.map +1 -0
- package/dist/adapters/http/middleware/built-in/authorization/module.d.ts +26 -2
- package/dist/adapters/http/middleware/built-in/authorization/module.d.ts.map +1 -1
- package/dist/adapters/http/middleware/built-in/authorization/module.mjs +67 -1
- package/dist/adapters/http/middleware/built-in/authorization/module.mjs.map +1 -1
- package/dist/adapters/http/middleware/built-in/authorization/types.d.ts +21 -1
- package/dist/adapters/http/middleware/built-in/authorization/types.d.ts.map +1 -1
- package/dist/adapters/http/middleware/built-in/basic.d.ts +2 -2
- package/dist/adapters/http/middleware/built-in/basic.d.ts.map +1 -1
- package/dist/adapters/http/middleware/built-in/basic.mjs.map +1 -1
- package/dist/adapters/http/middleware/built-in/cors.d.ts +8 -2
- package/dist/adapters/http/middleware/built-in/cors.d.ts.map +1 -1
- package/dist/adapters/http/middleware/built-in/cors.mjs +20 -3
- package/dist/adapters/http/middleware/built-in/cors.mjs.map +1 -1
- package/dist/adapters/http/middleware/built-in/error.d.ts +2 -2
- package/dist/adapters/http/middleware/built-in/error.d.ts.map +1 -1
- package/dist/adapters/http/middleware/built-in/error.mjs +10 -1
- package/dist/adapters/http/middleware/built-in/error.mjs.map +1 -1
- package/dist/adapters/http/middleware/built-in/index.d.ts +1 -4
- package/dist/adapters/http/middleware/built-in/index.d.ts.map +1 -1
- package/dist/adapters/http/middleware/built-in/index.mjs +3 -4
- package/dist/adapters/http/middleware/built-in/internal-http-client.d.ts +17 -0
- package/dist/adapters/http/middleware/built-in/internal-http-client.d.ts.map +1 -0
- package/dist/adapters/http/middleware/built-in/internal-http-client.mjs +27 -0
- package/dist/adapters/http/middleware/built-in/internal-http-client.mjs.map +1 -0
- package/dist/adapters/http/middleware/built-in/logger.mjs +1 -1
- package/dist/adapters/http/middleware/built-in/logger.mjs.map +1 -1
- package/dist/adapters/http/middleware/built-in/prometheus.d.ts +6 -5
- package/dist/adapters/http/middleware/built-in/prometheus.d.ts.map +1 -1
- package/dist/adapters/http/middleware/built-in/prometheus.mjs +3 -2
- package/dist/adapters/http/middleware/built-in/prometheus.mjs.map +1 -1
- package/dist/adapters/http/middleware/built-in/rate-limit.d.ts +2 -2
- package/dist/adapters/http/middleware/built-in/rate-limit.d.ts.map +1 -1
- package/dist/adapters/http/middleware/built-in/rate-limit.mjs +15 -0
- package/dist/adapters/http/middleware/built-in/rate-limit.mjs.map +1 -1
- package/dist/adapters/http/middleware/index.mjs +3 -4
- package/dist/adapters/http/request/constants.d.ts +1 -1
- package/dist/adapters/http/request/constants.d.ts.map +1 -1
- package/dist/adapters/http/request/constants.mjs +1 -5
- package/dist/adapters/http/request/constants.mjs.map +1 -1
- package/dist/adapters/http/request/helpers/index.d.ts +1 -1
- package/dist/adapters/http/request/helpers/index.d.ts.map +1 -1
- package/dist/adapters/http/request/helpers/index.mjs +2 -2
- package/dist/adapters/http/request/helpers/locale.d.ts +2 -1
- package/dist/adapters/http/request/helpers/locale.d.ts.map +1 -1
- package/dist/adapters/http/request/helpers/locale.mjs +1 -1
- package/dist/adapters/http/request/helpers/locale.mjs.map +1 -1
- package/dist/adapters/http/request/helpers/same-origin.d.ts +38 -0
- package/dist/adapters/http/request/helpers/same-origin.d.ts.map +1 -0
- package/dist/adapters/http/request/helpers/same-origin.mjs +68 -0
- package/dist/adapters/http/request/helpers/same-origin.mjs.map +1 -0
- package/dist/adapters/http/request/index.mjs +2 -2
- package/dist/adapters/http/request/permission/module.mjs +1 -1
- package/dist/adapters/http/request/permission/module.mjs.map +1 -1
- package/dist/adapters/http/request/types.d.ts +1 -2
- package/dist/adapters/http/request/types.d.ts.map +1 -1
- package/dist/adapters/shared/ldap/module.d.ts.map +1 -1
- package/dist/adapters/shared/ldap/module.mjs +4 -1
- package/dist/adapters/shared/ldap/module.mjs.map +1 -1
- package/dist/app/builder.d.ts +4 -4
- package/dist/app/builder.d.ts.map +1 -1
- package/dist/app/builder.mjs +7 -4
- package/dist/app/builder.mjs.map +1 -1
- package/dist/app/factory.d.ts +10 -0
- package/dist/app/factory.d.ts.map +1 -1
- package/dist/app/factory.mjs +26 -2
- package/dist/app/factory.mjs.map +1 -1
- package/dist/app/index.mjs +17 -19
- package/dist/app/modules/authentication/module.d.ts.map +1 -1
- package/dist/app/modules/authentication/module.mjs +15 -2
- package/dist/app/modules/authentication/module.mjs.map +1 -1
- package/dist/app/modules/authentication/repositories/session.d.ts +4 -1
- package/dist/app/modules/authentication/repositories/session.d.ts.map +1 -1
- package/dist/app/modules/authentication/repositories/session.mjs +20 -3
- package/dist/app/modules/authentication/repositories/session.mjs.map +1 -1
- package/dist/app/modules/components/index.d.ts +1 -0
- package/dist/app/modules/components/index.d.ts.map +1 -1
- package/dist/app/modules/components/module.d.ts +3 -1
- package/dist/app/modules/components/module.d.ts.map +1 -1
- package/dist/app/modules/components/module.mjs +26 -7
- package/dist/app/modules/components/module.mjs.map +1 -1
- package/dist/app/modules/components/types.d.ts +11 -0
- package/dist/app/modules/components/types.d.ts.map +1 -0
- package/dist/app/modules/config/app-origins.d.ts +10 -0
- package/dist/app/modules/config/app-origins.d.ts.map +1 -0
- package/dist/app/modules/config/app-origins.mjs +21 -0
- package/dist/app/modules/config/app-origins.mjs.map +1 -0
- package/dist/app/modules/config/constants.d.ts +23 -50
- package/dist/app/modules/config/constants.d.ts.map +1 -1
- package/dist/app/modules/config/constants.mjs +34 -51
- package/dist/app/modules/config/constants.mjs.map +1 -1
- package/dist/app/modules/config/index.d.ts +2 -3
- package/dist/app/modules/config/index.d.ts.map +1 -1
- package/dist/app/modules/config/index.mjs +4 -8
- package/dist/app/modules/config/module.d.ts +2 -2
- package/dist/app/modules/config/module.d.ts.map +1 -1
- package/dist/app/modules/config/module.mjs +1 -1
- package/dist/app/modules/config/module.mjs.map +1 -1
- package/dist/app/modules/config/read.d.ts +29 -0
- package/dist/app/modules/config/read.d.ts.map +1 -0
- package/dist/app/modules/config/read.mjs +65 -0
- package/dist/app/modules/config/read.mjs.map +1 -0
- package/dist/app/modules/config/types.d.ts +30 -397
- package/dist/app/modules/config/types.d.ts.map +1 -1
- package/dist/app/modules/config/validator.d.ts.map +1 -1
- package/dist/app/modules/config/validator.mjs +3 -87
- package/dist/app/modules/config/validator.mjs.map +1 -1
- package/dist/app/modules/database/index.d.ts +1 -0
- package/dist/app/modules/database/index.d.ts.map +1 -1
- package/dist/app/modules/database/index.mjs +2 -1
- package/dist/app/modules/database/migration.d.ts +33 -0
- package/dist/app/modules/database/migration.d.ts.map +1 -0
- package/dist/app/modules/database/migration.mjs +52 -0
- package/dist/app/modules/database/migration.mjs.map +1 -0
- package/dist/app/modules/database/module.d.ts.map +1 -1
- package/dist/app/modules/database/module.mjs +12 -6
- package/dist/app/modules/database/module.mjs.map +1 -1
- package/dist/app/modules/database/repositories/client/repository.d.ts +6 -1
- package/dist/app/modules/database/repositories/client/repository.d.ts.map +1 -1
- package/dist/app/modules/database/repositories/client/repository.mjs +21 -4
- package/dist/app/modules/database/repositories/client/repository.mjs.map +1 -1
- package/dist/app/modules/database/repositories/event/repository.d.ts +29 -2
- package/dist/app/modules/database/repositories/event/repository.d.ts.map +1 -1
- package/dist/app/modules/database/repositories/event/repository.mjs +42 -24
- package/dist/app/modules/database/repositories/event/repository.mjs.map +1 -1
- package/dist/app/modules/database/repositories/helpers.d.ts +24 -1
- package/dist/app/modules/database/repositories/helpers.d.ts.map +1 -1
- package/dist/app/modules/database/repositories/helpers.mjs +38 -1
- package/dist/app/modules/database/repositories/helpers.mjs.map +1 -1
- package/dist/app/modules/database/repositories/identity-provider/repository.d.ts +3 -1
- package/dist/app/modules/database/repositories/identity-provider/repository.d.ts.map +1 -1
- package/dist/app/modules/database/repositories/identity-provider/repository.mjs +3 -3
- package/dist/app/modules/database/repositories/identity-provider/repository.mjs.map +1 -1
- package/dist/app/modules/database/repositories/identity-provider-account/repository.mjs +4 -2
- package/dist/app/modules/database/repositories/identity-provider-account/repository.mjs.map +1 -1
- package/dist/app/modules/database/repositories/key/repository.mjs +1 -1
- package/dist/app/modules/database/repositories/permission/repository.mjs +1 -1
- package/dist/app/modules/database/repositories/policy/repository.mjs +1 -1
- package/dist/app/modules/database/repositories/role/repository.mjs +1 -1
- package/dist/app/modules/database/repositories/scope/repository.mjs +1 -1
- package/dist/app/modules/database/repositories/trust-anchor/repository.mjs +1 -1
- package/dist/app/modules/database/repositories/user/repository.d.ts +7 -2
- package/dist/app/modules/database/repositories/user/repository.d.ts.map +1 -1
- package/dist/app/modules/database/repositories/user/repository.mjs +21 -4
- package/dist/app/modules/database/repositories/user/repository.mjs.map +1 -1
- package/dist/app/modules/http/constants.d.ts +3 -1
- package/dist/app/modules/http/constants.d.ts.map +1 -1
- package/dist/app/modules/http/constants.mjs +3 -2
- package/dist/app/modules/http/constants.mjs.map +1 -1
- package/dist/app/modules/http/module.d.ts +30 -9
- package/dist/app/modules/http/module.d.ts.map +1 -1
- package/dist/app/modules/http/module.mjs +31 -33
- package/dist/app/modules/http/module.mjs.map +1 -1
- package/dist/app/modules/http/modules/controller.d.ts +4 -3
- package/dist/app/modules/http/modules/controller.d.ts.map +1 -1
- package/dist/app/modules/http/modules/controller.mjs +70 -38
- package/dist/app/modules/http/modules/controller.mjs.map +1 -1
- package/dist/app/modules/http/modules/middleware.d.ts +13 -22
- package/dist/app/modules/http/modules/middleware.d.ts.map +1 -1
- package/dist/app/modules/http/modules/middleware.mjs +20 -36
- package/dist/app/modules/http/modules/middleware.mjs.map +1 -1
- package/dist/app/modules/identity/module.mjs +4 -4
- package/dist/app/modules/identity/repositories/client.mjs +4 -2
- package/dist/app/modules/identity/repositories/client.mjs.map +1 -1
- package/dist/app/modules/identity/repositories/user.mjs +4 -2
- package/dist/app/modules/identity/repositories/user.mjs.map +1 -1
- package/dist/app/modules/index.mjs +21 -23
- package/dist/app/modules/logger/module.mjs +1 -1
- package/dist/app/modules/logger/module.mjs.map +1 -1
- package/dist/app/modules/mail/module.d.ts.map +1 -1
- package/dist/app/modules/mail/module.mjs.map +1 -1
- package/dist/app/modules/oauth2/constants.d.ts +3 -1
- package/dist/app/modules/oauth2/constants.d.ts.map +1 -1
- package/dist/app/modules/oauth2/constants.mjs +2 -0
- package/dist/app/modules/oauth2/constants.mjs.map +1 -1
- package/dist/app/modules/oauth2/module.d.ts.map +1 -1
- package/dist/app/modules/oauth2/module.mjs +14 -4
- package/dist/app/modules/oauth2/module.mjs.map +1 -1
- package/dist/app/modules/oauth2/repositories/client/repository.mjs +4 -2
- package/dist/app/modules/oauth2/repositories/client/repository.mjs.map +1 -1
- package/dist/app/modules/oauth2/repositories/consent/repository.d.ts.map +1 -1
- package/dist/app/modules/oauth2/repositories/consent/repository.mjs +3 -2
- package/dist/app/modules/oauth2/repositories/consent/repository.mjs.map +1 -1
- package/dist/app/modules/oauth2/repositories/console-login/index.d.ts +2 -0
- package/dist/app/modules/oauth2/repositories/console-login/index.d.ts.map +1 -0
- package/dist/app/modules/oauth2/repositories/console-login/index.mjs +5 -0
- package/dist/app/modules/oauth2/repositories/console-login/store.d.ts +19 -0
- package/dist/app/modules/oauth2/repositories/console-login/store.d.ts.map +1 -0
- package/dist/app/modules/oauth2/repositories/console-login/store.mjs +47 -0
- package/dist/app/modules/oauth2/repositories/console-login/store.mjs.map +1 -0
- package/dist/app/modules/oauth2/repositories/constants.d.ts +2 -0
- package/dist/app/modules/oauth2/repositories/constants.d.ts.map +1 -1
- package/dist/app/modules/oauth2/repositories/constants.mjs +2 -0
- package/dist/app/modules/oauth2/repositories/constants.mjs.map +1 -1
- package/dist/app/modules/oauth2/repositories/federated-login/index.d.ts +2 -0
- package/dist/app/modules/oauth2/repositories/federated-login/index.d.ts.map +1 -0
- package/dist/app/modules/oauth2/repositories/federated-login/index.mjs +5 -0
- package/dist/app/modules/oauth2/repositories/federated-login/store.d.ts +9 -0
- package/dist/app/modules/oauth2/repositories/federated-login/store.d.ts.map +1 -0
- package/dist/app/modules/oauth2/repositories/federated-login/store.mjs +33 -0
- package/dist/app/modules/oauth2/repositories/federated-login/store.mjs.map +1 -0
- package/dist/app/modules/oauth2/repositories/index.d.ts +2 -0
- package/dist/app/modules/oauth2/repositories/index.d.ts.map +1 -1
- package/dist/app/modules/oauth2/repositories/index.mjs +5 -1
- package/dist/app/modules/oauth2/repositories/session-token/repository.d.ts +2 -2
- package/dist/app/modules/oauth2/repositories/session-token/repository.d.ts.map +1 -1
- package/dist/app/modules/oauth2/repositories/session-token/repository.mjs +5 -3
- 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 +5 -6
- package/dist/app/modules/provisioning/module.mjs.map +1 -1
- package/dist/app/modules/provisioning/sources/composite/module.d.ts.map +1 -1
- package/dist/app/modules/provisioning/sources/composite/module.mjs +2 -1
- package/dist/app/modules/provisioning/sources/composite/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 +2 -1
- package/dist/app/modules/provisioning/sources/default/module.mjs.map +1 -1
- package/dist/app/modules/runtime/module.d.ts.map +1 -1
- package/dist/app/modules/runtime/module.mjs +2 -1
- package/dist/app/modules/runtime/module.mjs.map +1 -1
- package/dist/app/types.d.ts +16 -0
- package/dist/app/types.d.ts.map +1 -1
- package/dist/cli/commands/config.d.ts +40 -0
- package/dist/cli/commands/config.d.ts.map +1 -0
- package/dist/cli/commands/config.mjs +65 -0
- package/dist/cli/commands/config.mjs.map +1 -0
- package/dist/cli/commands/healthcheck.d.ts +3 -2
- package/dist/cli/commands/healthcheck.d.ts.map +1 -1
- package/dist/cli/commands/healthcheck.mjs +6 -3
- package/dist/cli/commands/healthcheck.mjs.map +1 -1
- package/dist/cli/commands/index.d.ts +3 -0
- package/dist/cli/commands/index.d.ts.map +1 -1
- package/dist/cli/commands/index.mjs +3 -1
- package/dist/cli/commands/migration.d.ts +3 -10
- package/dist/cli/commands/migration.d.ts.map +1 -1
- package/dist/cli/commands/migration.mjs +17 -9
- package/dist/cli/commands/migration.mjs.map +1 -1
- package/dist/cli/commands/shutdown.d.ts +16 -0
- package/dist/cli/commands/shutdown.d.ts.map +1 -0
- package/dist/cli/commands/shutdown.mjs +41 -0
- package/dist/cli/commands/shutdown.mjs.map +1 -0
- package/dist/cli/commands/start.d.ts +3 -2
- package/dist/cli/commands/start.d.ts.map +1 -1
- package/dist/cli/commands/start.mjs +3 -21
- package/dist/cli/commands/start.mjs.map +1 -1
- package/dist/cli/commands/types.d.ts.map +1 -0
- package/dist/cli/index.d.ts +8 -0
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.mjs.map +1 -1
- package/dist/cli/module.d.ts +0 -2
- package/dist/cli/module.d.ts.map +1 -1
- package/dist/cli/module.mjs +4 -3
- package/dist/cli/module.mjs.map +1 -1
- package/dist/components/oauth2-cleaner/module.d.ts +2 -2
- package/dist/components/oauth2-cleaner/module.d.ts.map +1 -1
- package/dist/components/oauth2-cleaner/module.mjs +10 -7
- package/dist/components/oauth2-cleaner/module.mjs.map +1 -1
- package/dist/core/authentication/index.mjs +2 -1
- package/dist/core/authentication/session/constants.d.ts +10 -0
- package/dist/core/authentication/session/constants.d.ts.map +1 -0
- package/dist/core/authentication/session/constants.mjs +16 -0
- package/dist/core/authentication/session/constants.mjs.map +1 -0
- package/dist/core/authentication/session/index.d.ts +1 -0
- package/dist/core/authentication/session/index.d.ts.map +1 -1
- package/dist/core/authentication/session/index.mjs +2 -1
- package/dist/core/authentication/session/module.d.ts +2 -1
- package/dist/core/authentication/session/module.d.ts.map +1 -1
- package/dist/core/authentication/session/module.mjs +7 -1
- package/dist/core/authentication/session/module.mjs.map +1 -1
- package/dist/core/authentication/session/types.d.ts +70 -1
- package/dist/core/authentication/session/types.d.ts.map +1 -1
- package/dist/core/authentication/session/types.mjs.map +1 -1
- package/dist/core/entities/client/schema.d.ts.map +1 -1
- package/dist/core/entities/client/schema.mjs +1 -2
- package/dist/core/entities/client/schema.mjs.map +1 -1
- package/dist/core/entities/client/service.d.ts.map +1 -1
- package/dist/core/entities/client/service.mjs +15 -1
- package/dist/core/entities/client/service.mjs.map +1 -1
- package/dist/core/entities/client/system-clients.d.ts +0 -5
- package/dist/core/entities/client/system-clients.d.ts.map +1 -1
- package/dist/core/entities/client/system-clients.mjs +0 -6
- package/dist/core/entities/client/system-clients.mjs.map +1 -1
- package/dist/core/entities/client/types.d.ts +12 -0
- package/dist/core/entities/client/types.d.ts.map +1 -1
- package/dist/core/entities/client-permission/service.mjs +1 -1
- package/dist/core/entities/client-permission/service.mjs.map +1 -1
- package/dist/core/entities/event/constants.d.ts +1 -6
- package/dist/core/entities/event/constants.d.ts.map +1 -1
- package/dist/core/entities/event/constants.mjs +1 -5
- package/dist/core/entities/event/constants.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 +17 -3
- package/dist/core/entities/event/entity-event-handler.mjs.map +1 -1
- package/dist/core/entities/event/service.d.ts.map +1 -1
- package/dist/core/entities/event/service.mjs +3 -3
- package/dist/core/entities/event/service.mjs.map +1 -1
- package/dist/core/entities/event/types.d.ts +15 -1
- package/dist/core/entities/event/types.d.ts.map +1 -1
- package/dist/core/entities/identity-provider/types.d.ts +9 -1
- package/dist/core/entities/identity-provider/types.d.ts.map +1 -1
- package/dist/core/entities/permission/service.mjs +1 -2
- package/dist/core/entities/permission/service.mjs.map +1 -1
- package/dist/core/entities/role-permission/service.mjs +1 -1
- package/dist/core/entities/role-permission/service.mjs.map +1 -1
- package/dist/core/entities/session/service.d.ts +13 -1
- package/dist/core/entities/session/service.d.ts.map +1 -1
- package/dist/core/entities/session/service.mjs +19 -16
- package/dist/core/entities/session/service.mjs.map +1 -1
- package/dist/core/entities/user/schema.d.ts.map +1 -1
- package/dist/core/entities/user/schema.mjs +1 -0
- package/dist/core/entities/user/schema.mjs.map +1 -1
- package/dist/core/entities/user/service.d.ts.map +1 -1
- package/dist/core/entities/user/service.mjs +21 -1
- package/dist/core/entities/user/service.mjs.map +1 -1
- package/dist/core/entities/user/types.d.ts +12 -0
- package/dist/core/entities/user/types.d.ts.map +1 -1
- package/dist/core/entities/user-permission/service.mjs +1 -1
- package/dist/core/entities/user-permission/service.mjs.map +1 -1
- package/dist/core/identity/index.mjs +2 -1
- package/dist/core/identity/permission/junction-grant.mjs +1 -1
- package/dist/core/identity/permission/junction-grant.mjs.map +1 -1
- package/dist/core/identity/provider/account/module.mjs +2 -2
- package/dist/core/identity/provider/account/module.mjs.map +1 -1
- package/dist/core/identity/provider/authentication/index.mjs +2 -1
- package/dist/core/identity/provider/authentication/protocols/index.mjs +2 -1
- package/dist/core/identity/provider/authentication/protocols/oauth2/assurance.d.ts +46 -0
- package/dist/core/identity/provider/authentication/protocols/oauth2/assurance.d.ts.map +1 -0
- package/dist/core/identity/provider/authentication/protocols/oauth2/assurance.mjs +89 -0
- package/dist/core/identity/provider/authentication/protocols/oauth2/assurance.mjs.map +1 -0
- package/dist/core/identity/provider/authentication/protocols/oauth2/index.d.ts +1 -0
- package/dist/core/identity/provider/authentication/protocols/oauth2/index.d.ts.map +1 -1
- package/dist/core/identity/provider/authentication/protocols/oauth2/index.mjs +2 -1
- package/dist/core/identity/provider/authentication/protocols/oauth2/module.d.ts.map +1 -1
- package/dist/core/identity/provider/authentication/protocols/oauth2/module.mjs +9 -2
- package/dist/core/identity/provider/authentication/protocols/oauth2/module.mjs.map +1 -1
- package/dist/core/identity/provider/index.mjs +2 -1
- package/dist/core/identity/registration/service.d.ts.map +1 -1
- package/dist/core/identity/registration/service.mjs +2 -1
- package/dist/core/identity/registration/service.mjs.map +1 -1
- package/dist/core/index.mjs +14 -4
- package/dist/core/oauth2/authorization/helpers.d.ts +14 -0
- package/dist/core/oauth2/authorization/helpers.d.ts.map +1 -1
- package/dist/core/oauth2/authorization/helpers.mjs +15 -2
- package/dist/core/oauth2/authorization/helpers.mjs.map +1 -1
- package/dist/core/oauth2/authorization/index.mjs +2 -2
- package/dist/core/oauth2/authorization/module.d.ts.map +1 -1
- package/dist/core/oauth2/authorization/module.mjs +6 -4
- package/dist/core/oauth2/authorization/module.mjs.map +1 -1
- package/dist/core/oauth2/authorization/state/types.d.ts +8 -0
- package/dist/core/oauth2/authorization/state/types.d.ts.map +1 -1
- package/dist/core/oauth2/backchannel-logout/constants.d.ts +16 -0
- package/dist/core/oauth2/backchannel-logout/constants.d.ts.map +1 -0
- package/dist/core/oauth2/backchannel-logout/constants.mjs +20 -0
- package/dist/core/oauth2/backchannel-logout/constants.mjs.map +1 -0
- package/dist/core/oauth2/backchannel-logout/index.d.ts +4 -0
- package/dist/core/oauth2/backchannel-logout/index.d.ts.map +1 -0
- package/dist/core/oauth2/backchannel-logout/index.mjs +6 -0
- package/dist/core/oauth2/backchannel-logout/module.d.ts +26 -0
- package/dist/core/oauth2/backchannel-logout/module.d.ts.map +1 -0
- package/dist/core/oauth2/backchannel-logout/module.mjs +78 -0
- package/dist/core/oauth2/backchannel-logout/module.mjs.map +1 -0
- package/dist/core/oauth2/backchannel-logout/types.d.ts +29 -0
- package/dist/core/oauth2/backchannel-logout/types.d.ts.map +1 -0
- package/dist/core/oauth2/console-login/constants.d.ts +19 -0
- package/dist/core/oauth2/console-login/constants.d.ts.map +1 -0
- package/dist/core/oauth2/console-login/constants.mjs +24 -0
- package/dist/core/oauth2/console-login/constants.mjs.map +1 -0
- package/dist/core/oauth2/console-login/index.d.ts +3 -0
- package/dist/core/oauth2/console-login/index.d.ts.map +1 -0
- package/dist/core/oauth2/console-login/index.mjs +5 -0
- package/dist/core/oauth2/console-login/types.d.ts +53 -0
- package/dist/core/oauth2/console-login/types.d.ts.map +1 -0
- package/dist/core/oauth2/end-session/service.mjs +1 -1
- package/dist/core/oauth2/end-session/service.mjs.map +1 -1
- package/dist/core/oauth2/federated-login/constants.d.ts +22 -0
- package/dist/core/oauth2/federated-login/constants.d.ts.map +1 -0
- package/dist/core/oauth2/federated-login/constants.mjs +27 -0
- package/dist/core/oauth2/federated-login/constants.mjs.map +1 -0
- package/dist/core/oauth2/federated-login/index.d.ts +1 -0
- package/dist/core/oauth2/federated-login/index.d.ts.map +1 -1
- package/dist/core/oauth2/federated-login/index.mjs +2 -1
- package/dist/core/oauth2/federated-login/module.d.ts +12 -3
- package/dist/core/oauth2/federated-login/module.d.ts.map +1 -1
- package/dist/core/oauth2/federated-login/module.mjs +98 -42
- package/dist/core/oauth2/federated-login/module.mjs.map +1 -1
- package/dist/core/oauth2/federated-login/types.d.ts +82 -24
- package/dist/core/oauth2/federated-login/types.d.ts.map +1 -1
- package/dist/core/oauth2/federated-login/types.mjs +5 -0
- package/dist/core/oauth2/federated-login/types.mjs.map +1 -1
- package/dist/core/oauth2/grant-types/authorize.mjs +1 -1
- package/dist/core/oauth2/grant-types/client-credentials.mjs +1 -1
- package/dist/core/oauth2/grant-types/identity.mjs +1 -1
- package/dist/core/oauth2/grant-types/password.mjs +1 -1
- package/dist/core/oauth2/grant-types/refresh-token.mjs +1 -1
- package/dist/core/oauth2/index.d.ts +4 -0
- package/dist/core/oauth2/index.d.ts.map +1 -1
- package/dist/core/oauth2/index.mjs +15 -4
- package/dist/core/oauth2/introspection/index.d.ts +3 -0
- package/dist/core/oauth2/introspection/index.d.ts.map +1 -0
- package/dist/core/oauth2/introspection/index.mjs +5 -0
- package/dist/core/oauth2/introspection/module.d.ts +14 -0
- package/dist/core/oauth2/introspection/module.d.ts.map +1 -0
- package/dist/core/oauth2/introspection/module.mjs +49 -0
- package/dist/core/oauth2/introspection/module.mjs.map +1 -0
- package/dist/core/oauth2/introspection/types.d.ts +45 -0
- package/dist/core/oauth2/introspection/types.d.ts.map +1 -0
- package/dist/core/oauth2/introspection/types.mjs +4 -0
- package/dist/core/oauth2/openid/claims.d.ts +20 -2
- package/dist/core/oauth2/openid/claims.d.ts.map +1 -1
- package/dist/core/oauth2/openid/claims.mjs +18 -4
- package/dist/core/oauth2/openid/claims.mjs.map +1 -1
- package/dist/core/oauth2/session-credential/constants.d.ts +30 -0
- package/dist/core/oauth2/session-credential/constants.d.ts.map +1 -0
- package/dist/core/oauth2/session-credential/constants.mjs +34 -0
- package/dist/core/oauth2/session-credential/constants.mjs.map +1 -0
- package/dist/core/oauth2/session-credential/index.d.ts +3 -0
- package/dist/core/oauth2/session-credential/index.d.ts.map +1 -0
- package/dist/core/oauth2/session-credential/index.mjs +6 -0
- package/dist/core/oauth2/session-credential/module.d.ts +31 -0
- package/dist/core/oauth2/session-credential/module.d.ts.map +1 -0
- package/dist/core/oauth2/session-credential/module.mjs +43 -0
- package/dist/core/oauth2/session-credential/module.mjs.map +1 -0
- package/dist/core/oauth2/session-token/constants.d.ts +10 -0
- package/dist/core/oauth2/session-token/constants.d.ts.map +1 -0
- package/dist/core/oauth2/session-token/constants.mjs +16 -0
- package/dist/core/oauth2/session-token/constants.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 +13 -2
- package/dist/core/oauth2/session-token/types.d.ts.map +1 -1
- package/dist/core/oauth2/token/verifier/module.d.ts.map +1 -1
- package/dist/core/oauth2/token/verifier/module.mjs +3 -3
- package/dist/core/oauth2/token/verifier/module.mjs.map +1 -1
- package/dist/core/provisioning/merge/module.mjs +5 -3
- package/dist/core/provisioning/merge/module.mjs.map +1 -1
- package/dist/core/query/module.mjs +1 -1
- package/dist/core/query/module.mjs.map +1 -1
- package/dist/core/security/policy/evaluator.mjs +1 -1
- package/dist/core/security/policy/evaluator.mjs.map +1 -1
- package/dist/index.mjs +62 -59
- package/dist/path.mjs +1 -1
- package/dist/swagger.json +573 -163
- package/dist/utils/error.d.ts +6 -0
- package/dist/utils/error.d.ts.map +1 -1
- package/dist/utils/error.mjs +6 -2
- package/dist/utils/error.mjs.map +1 -1
- package/dist/utils/index.mjs +2 -2
- package/package.json +32 -26
- package/dist/adapters/http/middleware/built-in/assets.d.ts +0 -11
- package/dist/adapters/http/middleware/built-in/assets.d.ts.map +0 -1
- package/dist/adapters/http/middleware/built-in/assets.mjs +0 -91
- package/dist/adapters/http/middleware/built-in/assets.mjs.map +0 -1
- package/dist/adapters/http/middleware/built-in/theme.d.ts +0 -15
- package/dist/adapters/http/middleware/built-in/theme.d.ts.map +0 -1
- package/dist/adapters/http/middleware/built-in/theme.mjs +0 -27
- package/dist/adapters/http/middleware/built-in/theme.mjs.map +0 -1
- package/dist/adapters/http/middleware/built-in/types.d.ts +0 -14
- package/dist/adapters/http/middleware/built-in/types.d.ts.map +0 -1
- package/dist/adapters/http/middleware/built-in/ui-http-client.d.ts +0 -15
- package/dist/adapters/http/middleware/built-in/ui-http-client.d.ts.map +0 -1
- package/dist/adapters/http/middleware/built-in/ui-http-client.mjs +0 -25
- package/dist/adapters/http/middleware/built-in/ui-http-client.mjs.map +0 -1
- package/dist/adapters/http/request/helpers/redirect.d.ts +0 -14
- package/dist/adapters/http/request/helpers/redirect.d.ts.map +0 -1
- package/dist/adapters/http/request/helpers/redirect.mjs +0 -36
- package/dist/adapters/http/request/helpers/redirect.mjs.map +0 -1
- package/dist/adapters/http/ui/account-console/index.d.ts +0 -4
- package/dist/adapters/http/ui/account-console/index.d.ts.map +0 -1
- package/dist/adapters/http/ui/account-console/index.mjs +0 -6
- package/dist/adapters/http/ui/account-console/module.d.ts +0 -28
- package/dist/adapters/http/ui/account-console/module.d.ts.map +0 -1
- package/dist/adapters/http/ui/account-console/module.mjs +0 -80
- package/dist/adapters/http/ui/account-console/module.mjs.map +0 -1
- package/dist/adapters/http/ui/account-console/ref.d.ts +0 -30
- package/dist/adapters/http/ui/account-console/ref.d.ts.map +0 -1
- package/dist/adapters/http/ui/account-console/ref.mjs +0 -50
- package/dist/adapters/http/ui/account-console/ref.mjs.map +0 -1
- package/dist/adapters/http/ui/account-console/types.d.ts +0 -11
- package/dist/adapters/http/ui/account-console/types.d.ts.map +0 -1
- package/dist/adapters/http/ui/auth-console/http-client.d.ts +0 -22
- package/dist/adapters/http/ui/auth-console/http-client.d.ts.map +0 -1
- package/dist/adapters/http/ui/auth-console/http-client.mjs.map +0 -1
- package/dist/adapters/http/ui/auth-console/index.d.ts +0 -6
- package/dist/adapters/http/ui/auth-console/index.d.ts.map +0 -1
- package/dist/adapters/http/ui/auth-console/index.mjs +0 -8
- package/dist/adapters/http/ui/auth-console/module.d.ts +0 -4
- package/dist/adapters/http/ui/auth-console/module.d.ts.map +0 -1
- package/dist/adapters/http/ui/auth-console/module.mjs +0 -73
- package/dist/adapters/http/ui/auth-console/module.mjs.map +0 -1
- package/dist/adapters/http/ui/auth-console/resolve.d.ts +0 -21
- package/dist/adapters/http/ui/auth-console/resolve.d.ts.map +0 -1
- package/dist/adapters/http/ui/auth-console/resolve.mjs +0 -53
- package/dist/adapters/http/ui/auth-console/resolve.mjs.map +0 -1
- package/dist/adapters/http/ui/auth-console/serve.d.ts +0 -9
- package/dist/adapters/http/ui/auth-console/serve.d.ts.map +0 -1
- package/dist/adapters/http/ui/auth-console/serve.mjs +0 -35
- package/dist/adapters/http/ui/auth-console/serve.mjs.map +0 -1
- package/dist/adapters/http/ui/auth-console/types.d.ts +0 -26
- package/dist/adapters/http/ui/auth-console/types.d.ts.map +0 -1
- package/dist/adapters/http/ui/console-packages/index.d.ts.map +0 -1
- package/dist/adapters/http/ui/console-packages/index.mjs +0 -5
- package/dist/adapters/http/ui/console-packages/module.d.ts +0 -33
- package/dist/adapters/http/ui/console-packages/module.d.ts.map +0 -1
- package/dist/adapters/http/ui/console-packages/module.mjs +0 -70
- package/dist/adapters/http/ui/console-packages/module.mjs.map +0 -1
- package/dist/adapters/http/ui/console-packages/types.d.ts +0 -12
- package/dist/adapters/http/ui/console-packages/types.d.ts.map +0 -1
- package/dist/adapters/http/ui/index.d.ts +0 -6
- package/dist/adapters/http/ui/index.d.ts.map +0 -1
- package/dist/adapters/http/ui/index.mjs +0 -25
- package/dist/adapters/http/ui/shared/html.d.ts +0 -76
- package/dist/adapters/http/ui/shared/html.d.ts.map +0 -1
- package/dist/adapters/http/ui/shared/html.mjs +0 -104
- package/dist/adapters/http/ui/shared/html.mjs.map +0 -1
- package/dist/adapters/http/ui/shared/index.d.ts +0 -2
- package/dist/adapters/http/ui/shared/index.d.ts.map +0 -1
- package/dist/adapters/http/ui/shared/index.mjs +0 -5
- package/dist/adapters/http/ui/theme/apply.d.ts +0 -12
- package/dist/adapters/http/ui/theme/apply.d.ts.map +0 -1
- package/dist/adapters/http/ui/theme/apply.mjs +0 -29
- package/dist/adapters/http/ui/theme/apply.mjs.map +0 -1
- package/dist/adapters/http/ui/theme/assets.d.ts +0 -20
- package/dist/adapters/http/ui/theme/assets.d.ts.map +0 -1
- package/dist/adapters/http/ui/theme/assets.mjs +0 -86
- package/dist/adapters/http/ui/theme/assets.mjs.map +0 -1
- package/dist/adapters/http/ui/theme/constants.d.ts +0 -16
- package/dist/adapters/http/ui/theme/constants.d.ts.map +0 -1
- package/dist/adapters/http/ui/theme/constants.mjs +0 -20
- package/dist/adapters/http/ui/theme/constants.mjs.map +0 -1
- package/dist/adapters/http/ui/theme/contract/constants.d.ts +0 -120
- package/dist/adapters/http/ui/theme/contract/constants.d.ts.map +0 -1
- package/dist/adapters/http/ui/theme/contract/constants.mjs +0 -136
- package/dist/adapters/http/ui/theme/contract/constants.mjs.map +0 -1
- package/dist/adapters/http/ui/theme/contract/head.d.ts +0 -12
- package/dist/adapters/http/ui/theme/contract/head.d.ts.map +0 -1
- package/dist/adapters/http/ui/theme/contract/head.mjs +0 -61
- package/dist/adapters/http/ui/theme/contract/head.mjs.map +0 -1
- package/dist/adapters/http/ui/theme/contract/index.d.ts +0 -6
- package/dist/adapters/http/ui/theme/contract/index.d.ts.map +0 -1
- package/dist/adapters/http/ui/theme/contract/index.mjs +0 -8
- package/dist/adapters/http/ui/theme/contract/manifest.d.ts +0 -25
- package/dist/adapters/http/ui/theme/contract/manifest.d.ts.map +0 -1
- package/dist/adapters/http/ui/theme/contract/manifest.mjs +0 -77
- package/dist/adapters/http/ui/theme/contract/manifest.mjs.map +0 -1
- package/dist/adapters/http/ui/theme/contract/types.d.ts +0 -26
- package/dist/adapters/http/ui/theme/contract/types.d.ts.map +0 -1
- package/dist/adapters/http/ui/theme/contract/utils.d.ts +0 -11
- package/dist/adapters/http/ui/theme/contract/utils.d.ts.map +0 -1
- package/dist/adapters/http/ui/theme/contract/utils.mjs +0 -22
- package/dist/adapters/http/ui/theme/contract/utils.mjs.map +0 -1
- package/dist/adapters/http/ui/theme/index.d.ts +0 -7
- package/dist/adapters/http/ui/theme/index.d.ts.map +0 -1
- package/dist/adapters/http/ui/theme/index.mjs +0 -13
- package/dist/adapters/http/ui/theme/module.d.ts +0 -79
- package/dist/adapters/http/ui/theme/module.d.ts.map +0 -1
- package/dist/adapters/http/ui/theme/module.mjs +0 -206
- package/dist/adapters/http/ui/theme/module.mjs.map +0 -1
- package/dist/adapters/http/ui/theme/types.d.ts +0 -42
- package/dist/adapters/http/ui/theme/types.d.ts.map +0 -1
- package/dist/app/modules/config/helpers.d.ts +0 -9
- package/dist/app/modules/config/helpers.d.ts.map +0 -1
- package/dist/app/modules/config/helpers.mjs +0 -22
- package/dist/app/modules/config/helpers.mjs.map +0 -1
- package/dist/app/modules/config/normalize.d.ts +0 -3
- package/dist/app/modules/config/normalize.d.ts.map +0 -1
- package/dist/app/modules/config/normalize.mjs +0 -117
- package/dist/app/modules/config/normalize.mjs.map +0 -1
- package/dist/app/modules/config/origins.d.ts +0 -25
- package/dist/app/modules/config/origins.d.ts.map +0 -1
- package/dist/app/modules/config/origins.mjs +0 -46
- package/dist/app/modules/config/origins.mjs.map +0 -1
- package/dist/app/modules/config/read/env.d.ts +0 -3
- package/dist/app/modules/config/read/env.d.ts.map +0 -1
- package/dist/app/modules/config/read/env.mjs +0 -139
- package/dist/app/modules/config/read/env.mjs.map +0 -1
- package/dist/app/modules/config/read/fs.d.ts +0 -3
- package/dist/app/modules/config/read/fs.d.ts.map +0 -1
- package/dist/app/modules/config/read/fs.mjs +0 -60
- package/dist/app/modules/config/read/fs.mjs.map +0 -1
- package/dist/app/modules/config/read/index.d.ts +0 -5
- package/dist/app/modules/config/read/index.d.ts.map +0 -1
- package/dist/app/modules/config/read/index.mjs +0 -7
- package/dist/app/modules/config/read/module.d.ts +0 -4
- package/dist/app/modules/config/read/module.d.ts.map +0 -1
- package/dist/app/modules/config/read/module.mjs +0 -29
- package/dist/app/modules/config/read/module.mjs.map +0 -1
- package/dist/app/modules/config/read/types.d.ts +0 -9
- package/dist/app/modules/config/read/types.d.ts.map +0 -1
- package/dist/app/modules/config/trust-proxy.d.ts +0 -28
- package/dist/app/modules/config/trust-proxy.d.ts.map +0 -1
- package/dist/app/modules/config/trust-proxy.mjs +0 -64
- package/dist/app/modules/config/trust-proxy.mjs.map +0 -1
- package/dist/cli/config.d.ts +0 -18
- package/dist/cli/config.d.ts.map +0 -1
- package/dist/cli/config.mjs +0 -34
- package/dist/cli/config.mjs.map +0 -1
- package/dist/cli/types.d.ts.map +0 -1
- package/dist/utils/host.d.ts +0 -2
- package/dist/utils/host.d.ts.map +0 -1
- package/dist/utils/host.mjs +0 -12
- package/dist/utils/host.mjs.map +0 -1
- /package/dist/adapters/http/{middleware/built-in → controllers/workflows/account}/types.mjs +0 -0
- /package/dist/adapters/http/{ui/console-packages → controllers/workflows/admin}/index.d.ts +0 -0
- /package/dist/adapters/http/{ui/account-console → controllers/workflows/admin}/types.mjs +0 -0
- /package/dist/adapters/http/{ui/auth-console → controllers/workflows/console-login}/types.mjs +0 -0
- /package/dist/adapters/http/{ui/console-packages → internal-client}/types.mjs +0 -0
- /package/dist/{adapters/http/ui/theme/contract → app/modules/components}/types.mjs +0 -0
- /package/dist/cli/{types.d.ts → commands/types.d.ts} +0 -0
- /package/dist/{adapters/http/ui/theme → cli/commands}/types.mjs +0 -0
- /package/dist/{app/modules/config/read → core/oauth2/backchannel-logout}/types.mjs +0 -0
- /package/dist/{cli → core/oauth2/console-login}/types.mjs +0 -0
|
@@ -2,7 +2,7 @@ import "node:path";
|
|
|
2
2
|
import "node:url";
|
|
3
3
|
import.meta.url;
|
|
4
4
|
import { toIdentityPolicyData } from "../../identity/permission/identity-policy-data.mjs";
|
|
5
|
-
import { EventName, EventRefType, EventScope, IdentityType } from "@authup/core-kit";
|
|
5
|
+
import { EventName, EventRefType, EventScope, IdentityType, SessionAuthMethod } from "@authup/core-kit";
|
|
6
6
|
import { hasInstanceof } from "@authup/errors";
|
|
7
7
|
import { OAUTH2_ACCESS_DENIED_ERROR_INSTANCE, OAUTH2_LOGIN_REQUIRED_ERROR_INSTANCE, OAUTH2_MFA_REQUIRED_ERROR_INSTANCE, OAuth2AccessDeniedError, OAuth2AuthenticationContextClass, OAuth2AuthorizationPrompt, OAuth2AuthorizationResponseType, OAuth2GrantError, OAuth2LoginRequiredError, OAuth2MfaRequiredError, OAuth2RequestError, OAuth2ResponseTypeError } from "@authup/specs";
|
|
8
8
|
//#region src/core/oauth2/authorization/module.ts
|
|
@@ -97,8 +97,10 @@ var OAuth2Authorization = class {
|
|
|
97
97
|
}
|
|
98
98
|
if (this.mfaChallengeProvider && identity.type === IdentityType.USER) {
|
|
99
99
|
const challenge = await this.mfaChallengeProvider.challenge(identity.data.id, { issueMaterial: false });
|
|
100
|
-
if (
|
|
101
|
-
|
|
100
|
+
if (!(session?.authMethod === SessionAuthMethod.EXTERNAL)) {
|
|
101
|
+
if (challenge.required && !session?.mfaAt) throw OAuth2MfaRequiredError.challengeRequired();
|
|
102
|
+
if (challenge.enrollmentRequired) throw OAuth2MfaRequiredError.enrollmentRequired();
|
|
103
|
+
}
|
|
102
104
|
if (challenge.required && data.acr_values) {
|
|
103
105
|
if (data.acr_values.split(" ").includes(OAuth2AuthenticationContextClass.MFA)) {
|
|
104
106
|
const mfaAtSeconds = session?.mfaAt ? Math.floor(new Date(session.mfaAt).getTime() / 1e3) : null;
|
|
@@ -114,7 +116,7 @@ var OAuth2Authorization = class {
|
|
|
114
116
|
if (options.client?.accessPolicyId) {
|
|
115
117
|
let allowed = false;
|
|
116
118
|
const subject = toIdentityPolicyData(identity);
|
|
117
|
-
if (this.accessPolicyEvaluator
|
|
119
|
+
if (subject && this.accessPolicyEvaluator) allowed = await this.accessPolicyEvaluator.evaluate(options.client.accessPolicyId, subject);
|
|
118
120
|
if (!allowed) throw OAuth2AccessDeniedError.forClient(options.redirectUriVerified && data.redirect_uri ? {
|
|
119
121
|
redirectUri: data.redirect_uri,
|
|
120
122
|
state: data.state ?? null
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"module.mjs","names":["EventName","EventRefType","EventScope","IdentityType","hasInstanceof","OAUTH2_ACCESS_DENIED_ERROR_INSTANCE","OAUTH2_LOGIN_REQUIRED_ERROR_INSTANCE","OAUTH2_MFA_REQUIRED_ERROR_INSTANCE","OAuth2AccessDeniedError","OAuth2AuthenticationContextClass","OAuth2AuthorizationPrompt","OAuth2AuthorizationResponseType","OAuth2GrantError","OAuth2LoginRequiredError","OAuth2MfaRequiredError","OAuth2RequestError","OAuth2ResponseTypeError","toIdentityPolicyData","DEFAULT_PROMPT_LOGIN_MAX_AGE","DEFAULT_MFA_FRESHNESS_MAX_AGE","OAuth2Authorization","codeIssuer","sessionManager","eventService","metrics","promptLoginMaxAge","mfaFreshnessMaxAge","mfaChallengeProvider","accessPolicyEvaluator","ctx","authorize","data","identity","options","result","authorizeInner","record","scope","OAUTH2","name","AUTHORIZE","refType","CLIENT","refId","client","id","client_id","clientId","sessionId","actorType","type","actorId","actorName","realmId","realm_id","reason","builtIn","recordAuthorize","e","AUTHORIZE_FAILED","responseTypes","response_type","Array","isArray","split","responseType","CODE","unsupported","includes","redirect_uri","redirectUriMismatch","output","redirectUri","state","identityInvalid","realmMismatch","nowSeconds","Math","floor","Date","now","authTime","session","findOneById","createdAt","getTime","USER","challenge","issueMaterial","required","mfaAt","challengeRequired","enrollmentRequired","acr_values","acrValues","MFA","mfaAtSeconds","stepUpRequired","prompts","prompt","LOGIN","reauthenticationRequired","max_age","maxAge","Number","isFinite","accessPolicyId","allowed","subject","evaluate","forClient","redirectUriVerified","undefined","codeEntity","issue","authMethod","authorizationCode"],"sources":["../../../../src/core/oauth2/authorization/module.ts"],"sourcesContent":["/*\n * Copyright (c) 2024.\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 {\n Identity, \n OAuth2AuthorizationCode, \n OAuth2AuthorizationCodeRequest, \n Session,\n} from '@authup/core-kit';\nimport {\n EventName, \n EventRefType, \n EventScope, \n IdentityType,\n} from '@authup/core-kit';\nimport { hasInstanceof } from '@authup/errors';\nimport {\n OAUTH2_ACCESS_DENIED_ERROR_INSTANCE,\n OAUTH2_LOGIN_REQUIRED_ERROR_INSTANCE,\n OAUTH2_MFA_REQUIRED_ERROR_INSTANCE,\n OAuth2AccessDeniedError,\n OAuth2AuthenticationContextClass,\n OAuth2AuthorizationPrompt,\n OAuth2AuthorizationResponseType,\n OAuth2GrantError,\n OAuth2LoginRequiredError,\n OAuth2MfaRequiredError,\n OAuth2RequestError,\n OAuth2ResponseTypeError,\n} from '@authup/specs';\nimport type { IOAuth2AuthorizationCodeIssuer } from './code/index.ts';\nimport type { IOAuth2AccessPolicyEvaluator } from '../access-policy/index.ts';\nimport { toIdentityPolicyData } from '../../identity/permission/identity-policy-data.ts';\nimport type {\n OAuth2AuthorizationManagerContext,\n OAuth2AuthorizationOptions,\n OAuth2AuthorizationResult,\n} from './types.ts';\nimport type { ISessionManager } from '../../authentication/index.ts';\nimport type { IEventService, IUserAuthenticatorChallengeProvider } from '../../entities/index.ts';\nimport type { IAuthFlowMetrics } from '../../metrics/index.ts';\n\nconst DEFAULT_PROMPT_LOGIN_MAX_AGE = 60;\n\n// Deliberately 60 (not 0, deviating from the plan-050 sketch): the hosted\n// challenge round-trip (stamp mfa_at → retry POST /authorize) takes seconds,\n// so a 0-window step-up could never be satisfied and would loop the ladder.\nconst DEFAULT_MFA_FRESHNESS_MAX_AGE = 60;\n\nexport class OAuth2Authorization {\n protected codeIssuer : IOAuth2AuthorizationCodeIssuer;\n\n protected sessionManager : ISessionManager;\n\n protected eventService? : IEventService;\n\n protected metrics? : IAuthFlowMetrics;\n\n protected promptLoginMaxAge : number;\n\n protected mfaFreshnessMaxAge : number;\n\n protected mfaChallengeProvider? : IUserAuthenticatorChallengeProvider;\n\n protected accessPolicyEvaluator? : IOAuth2AccessPolicyEvaluator;\n\n constructor(ctx: OAuth2AuthorizationManagerContext) {\n this.codeIssuer = ctx.codeIssuer;\n this.sessionManager = ctx.sessionManager;\n this.eventService = ctx.eventService;\n this.metrics = ctx.metrics;\n this.accessPolicyEvaluator = ctx.accessPolicyEvaluator;\n this.promptLoginMaxAge = ctx.promptLoginMaxAge ?? DEFAULT_PROMPT_LOGIN_MAX_AGE;\n this.mfaFreshnessMaxAge = ctx.mfaFreshnessMaxAge ?? DEFAULT_MFA_FRESHNESS_MAX_AGE;\n this.mfaChallengeProvider = ctx.mfaChallengeProvider;\n }\n\n /**\n * Authorize with validated codeRequest.\n *\n * @param data\n * @param identity\n * @param options\n */\n async authorize(\n data: OAuth2AuthorizationCodeRequest,\n identity: Identity,\n options: OAuth2AuthorizationOptions = {},\n ) : Promise<OAuth2AuthorizationResult> {\n try {\n const result = await this.authorizeInner(data, identity, options);\n\n await this.eventService?.record({\n scope: EventScope.OAUTH2,\n name: EventName.AUTHORIZE,\n refType: EventRefType.CLIENT,\n refId: options.client?.id ?? data.client_id ?? null,\n clientId: options.client?.id ?? data.client_id ?? null,\n sessionId: options.sessionId ?? null,\n actorType: identity.type,\n actorId: identity.data.id,\n actorName: identity.data.name,\n realmId: data.realm_id ?? null,\n data: {\n reason: options.client?.builtIn ? 'autoConsent' : 'consent',\n ...(data.scope ? { scope: data.scope } : {}),\n },\n });\n this.metrics?.recordAuthorize('issued');\n\n return result;\n } catch (e) {\n if (hasInstanceof(e, OAUTH2_ACCESS_DENIED_ERROR_INSTANCE)) {\n await this.eventService?.record({\n scope: EventScope.OAUTH2,\n name: EventName.AUTHORIZE_FAILED,\n refType: EventRefType.CLIENT,\n refId: options.client?.id ?? data.client_id ?? null,\n clientId: options.client?.id ?? data.client_id ?? null,\n sessionId: options.sessionId ?? null,\n actorType: identity.type,\n actorId: identity.data.id,\n actorName: identity.data.name,\n realmId: data.realm_id ?? null,\n data: { reason: 'accessPolicy' },\n });\n this.metrics?.recordAuthorize('denied');\n } else if (hasInstanceof(e, OAUTH2_LOGIN_REQUIRED_ERROR_INSTANCE)) {\n this.metrics?.recordAuthorize('login_required');\n } else if (hasInstanceof(e, OAUTH2_MFA_REQUIRED_ERROR_INSTANCE)) {\n this.metrics?.recordAuthorize('mfa_required');\n } else {\n this.metrics?.recordAuthorize('error');\n }\n\n throw e;\n }\n }\n\n protected async authorizeInner(\n data: OAuth2AuthorizationCodeRequest,\n identity: Identity,\n options: OAuth2AuthorizationOptions = {},\n ) : Promise<OAuth2AuthorizationResult> {\n // OAuth 2.1 posture: only the authorization-code response type is\n // supported — implicit/hybrid (token, id_token, none) were dropped\n // (plan 042 item 3). Defense in depth behind the request validator.\n let responseTypes : string[] = [];\n if (data.response_type) {\n responseTypes = Array.isArray(data.response_type) ?\n data.response_type :\n data.response_type.split(' ');\n }\n\n for (const responseType of responseTypes) {\n if (responseType !== OAuth2AuthorizationResponseType.CODE) {\n throw OAuth2ResponseTypeError.unsupported();\n }\n }\n\n if (!responseTypes.includes(OAuth2AuthorizationResponseType.CODE)) {\n throw OAuth2ResponseTypeError.unsupported();\n }\n\n if (!data.redirect_uri) {\n throw OAuth2GrantError.redirectUriMismatch();\n }\n\n const output : OAuth2AuthorizationResult = {\n redirectUri: data.redirect_uri,\n ...(data.state ? { state: data.state } : {}),\n };\n\n if (!identity) {\n throw OAuth2RequestError.identityInvalid();\n }\n\n // Realm binding: the code-request verifier stamped data.realm_id with the\n // resolved client's realm. The authenticated identity must belong to that\n // same realm — otherwise a lingering session for realm A could silently\n // mint a code/token for realm B's client (confused deputy). The error body\n // deliberately carries no identity data (no realm-enumeration oracle).\n // The comparison reads the scalar realmId column, NOT the realm\n // relation — the relation may simply not be loaded on the resolved\n // identity. An identity without a realmId fails closed the same way —\n // clean login_required, never a TypeError.\n if (\n data.realm_id &&\n identity.data.realmId !== data.realm_id\n ) {\n throw OAuth2LoginRequiredError.realmMismatch();\n }\n\n // Authentication time = the backing session's creation instant (NOT\n // refreshed_at — a token refresh must not reset it). Session-less flows\n // (e.g. HTTP Basic authorize) present live credentials on this request,\n // so the authentication time is \"now\".\n const nowSeconds = Math.floor(Date.now() / 1000);\n let authTime = nowSeconds;\n let session : Session | null = null;\n if (options.sessionId) {\n session = await this.sessionManager.findOneById(options.sessionId);\n if (session && session.createdAt) {\n authTime = Math.floor(new Date(session.createdAt).getTime() / 1000);\n }\n }\n\n // MFA backstop (plan 049) — the authoritative server-side gate; the\n // hosted UI's challenge step is convenience. The proof is session-bound\n // (mfa_at — stamped by the challenge endpoint or the password grant's\n // otp param), so a session-less flow (HTTP Basic) cannot carry one and\n // fails closed while the user holds a confirmed device. A user without\n // a device under mfaRequired is routed to inline enrollment.\n if (this.mfaChallengeProvider && identity.type === IdentityType.USER) {\n // requirement flags only — the interactive challenge material (the\n // webauthn nonce) is issued by the status endpoint, not this backstop.\n const challenge = await this.mfaChallengeProvider.challenge(\n identity.data.id,\n { issueMaterial: false },\n );\n if (challenge.required && !session?.mfaAt) {\n throw OAuth2MfaRequiredError.challengeRequired();\n }\n\n if (challenge.enrollmentRequired) {\n throw OAuth2MfaRequiredError.enrollmentRequired();\n }\n\n // Step-up (plan 050 stage 3): a requested `acr_values` containing\n // urn:authup:mfa is a TRIGGER (Auth0/Keycloak stance) — the proof\n // must additionally be FRESH (mfaFreshnessMaxAge window, mirroring\n // promptLoginMaxAge's absorb-the-round-trip semantics). Enforced\n // only while the user actually holds a factor — per OIDC Core\n // §5.5.1.1 acr is voluntary, so an unsatisfiable request degrades\n // to the achieved acr instead of bricking the RP.\n if (challenge.required && data.acr_values) {\n const acrValues = data.acr_values.split(' ');\n if (acrValues.includes(OAuth2AuthenticationContextClass.MFA)) {\n const mfaAtSeconds = session?.mfaAt ?\n Math.floor(new Date(session.mfaAt).getTime() / 1000) :\n null;\n if (mfaAtSeconds === null || nowSeconds - mfaAtSeconds > this.mfaFreshnessMaxAge) {\n throw OAuth2MfaRequiredError.stepUpRequired();\n }\n }\n }\n }\n\n // OIDC §3.1.2.1 prompt=login / max_age freshness (enforced only when\n // requested — a plain authorize never throws here). The hosted page\n // renders the login form for prompt=login; this is the server backstop.\n const prompts = data.prompt ? data.prompt.split(' ') : [];\n if (\n prompts.includes(OAuth2AuthorizationPrompt.LOGIN) &&\n nowSeconds - authTime > this.promptLoginMaxAge\n ) {\n throw OAuth2LoginRequiredError.reauthenticationRequired();\n }\n\n if (\n typeof data.max_age !== 'undefined' &&\n data.max_age !== null\n ) {\n const maxAge = Number(data.max_age);\n if (\n Number.isFinite(maxAge) &&\n nowSeconds - authTime > maxAge\n ) {\n throw OAuth2LoginRequiredError.reauthenticationRequired();\n }\n }\n\n // Application access policy (plan 052) — the last gate before\n // issuance: a denial is only revealed to a fully-authenticated\n // (incl. second-factor) identity. A client carrying a policy id with\n // no wired evaluator denies too (never silently allow a configured\n // gate). The redirect target rides the error only when the\n // redirect_uri was pattern-verified (RFC 6749 §4.1.2.1).\n if (options.client?.accessPolicyId) {\n let allowed = false;\n\n const subject = toIdentityPolicyData(identity);\n if (this.accessPolicyEvaluator && subject) {\n allowed = await this.accessPolicyEvaluator.evaluate(\n options.client.accessPolicyId,\n subject,\n );\n }\n\n if (!allowed) {\n throw OAuth2AccessDeniedError.forClient(\n options.redirectUriVerified && data.redirect_uri ?\n { redirectUri: data.redirect_uri, state: data.state ?? null } :\n undefined,\n );\n }\n }\n\n // The id_token is NOT minted here — the /token exchange mints it after\n // resolving the real backing session, so its `sid` is authoritative\n // (plan 042 item 6). The code carries the authentication instant.\n const codeEntity : OAuth2AuthorizationCode = await this.codeIssuer.issue(\n data,\n identity,\n {\n sessionId: options.sessionId,\n authTime,\n authMethod: session?.authMethod ?? null,\n },\n );\n\n output.authorizationCode = codeEntity.id;\n\n return output;\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"module.mjs","names":["EventName","EventRefType","EventScope","IdentityType","SessionAuthMethod","hasInstanceof","OAUTH2_ACCESS_DENIED_ERROR_INSTANCE","OAUTH2_LOGIN_REQUIRED_ERROR_INSTANCE","OAUTH2_MFA_REQUIRED_ERROR_INSTANCE","OAuth2AccessDeniedError","OAuth2AuthenticationContextClass","OAuth2AuthorizationPrompt","OAuth2AuthorizationResponseType","OAuth2GrantError","OAuth2LoginRequiredError","OAuth2MfaRequiredError","OAuth2RequestError","OAuth2ResponseTypeError","toIdentityPolicyData","DEFAULT_PROMPT_LOGIN_MAX_AGE","DEFAULT_MFA_FRESHNESS_MAX_AGE","OAuth2Authorization","codeIssuer","sessionManager","eventService","metrics","promptLoginMaxAge","mfaFreshnessMaxAge","mfaChallengeProvider","accessPolicyEvaluator","ctx","authorize","data","identity","options","result","authorizeInner","record","scope","OAUTH2","name","AUTHORIZE","refType","CLIENT","refId","client","id","client_id","clientId","sessionId","actorType","type","actorId","actorName","realmId","realm_id","reason","builtIn","recordAuthorize","e","AUTHORIZE_FAILED","responseTypes","response_type","Array","isArray","split","responseType","CODE","unsupported","includes","redirect_uri","redirectUriMismatch","output","redirectUri","state","identityInvalid","realmMismatch","nowSeconds","Math","floor","Date","now","authTime","session","findOneById","createdAt","getTime","USER","challenge","issueMaterial","externallyAuthenticated","authMethod","EXTERNAL","required","mfaAt","challengeRequired","enrollmentRequired","acr_values","acrValues","MFA","mfaAtSeconds","stepUpRequired","prompts","prompt","LOGIN","reauthenticationRequired","max_age","maxAge","Number","isFinite","accessPolicyId","allowed","subject","evaluate","forClient","redirectUriVerified","undefined","codeEntity","issue","authorizationCode"],"sources":["../../../../src/core/oauth2/authorization/module.ts"],"sourcesContent":["/*\n * Copyright (c) 2024.\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 {\n Identity, \n OAuth2AuthorizationCode, \n OAuth2AuthorizationCodeRequest, \n Session,\n} from '@authup/core-kit';\nimport {\n EventName, \n EventRefType, \n EventScope, \n IdentityType,\n SessionAuthMethod,\n} from '@authup/core-kit';\nimport { hasInstanceof } from '@authup/errors';\nimport {\n OAUTH2_ACCESS_DENIED_ERROR_INSTANCE,\n OAUTH2_LOGIN_REQUIRED_ERROR_INSTANCE,\n OAUTH2_MFA_REQUIRED_ERROR_INSTANCE,\n OAuth2AccessDeniedError,\n OAuth2AuthenticationContextClass,\n OAuth2AuthorizationPrompt,\n OAuth2AuthorizationResponseType,\n OAuth2GrantError,\n OAuth2LoginRequiredError,\n OAuth2MfaRequiredError,\n OAuth2RequestError,\n OAuth2ResponseTypeError,\n} from '@authup/specs';\nimport type { IOAuth2AuthorizationCodeIssuer } from './code/index.ts';\nimport type { IOAuth2AccessPolicyEvaluator } from '../access-policy/index.ts';\nimport { toIdentityPolicyData } from '../../identity/permission/identity-policy-data.ts';\nimport type {\n OAuth2AuthorizationManagerContext,\n OAuth2AuthorizationOptions,\n OAuth2AuthorizationResult,\n} from './types.ts';\nimport type { ISessionManager } from '../../authentication/index.ts';\nimport type { IEventService, IUserAuthenticatorChallengeProvider } from '../../entities/index.ts';\nimport type { IAuthFlowMetrics } from '../../metrics/index.ts';\n\nconst DEFAULT_PROMPT_LOGIN_MAX_AGE = 60;\n\n// Deliberately 60 (not 0, deviating from the plan-050 sketch): the hosted\n// challenge round-trip (stamp mfa_at → retry POST /authorize) takes seconds,\n// so a 0-window step-up could never be satisfied and would loop the ladder.\nconst DEFAULT_MFA_FRESHNESS_MAX_AGE = 60;\n\nexport class OAuth2Authorization {\n protected codeIssuer : IOAuth2AuthorizationCodeIssuer;\n\n protected sessionManager : ISessionManager;\n\n protected eventService? : IEventService;\n\n protected metrics? : IAuthFlowMetrics;\n\n protected promptLoginMaxAge : number;\n\n protected mfaFreshnessMaxAge : number;\n\n protected mfaChallengeProvider? : IUserAuthenticatorChallengeProvider;\n\n protected accessPolicyEvaluator? : IOAuth2AccessPolicyEvaluator;\n\n constructor(ctx: OAuth2AuthorizationManagerContext) {\n this.codeIssuer = ctx.codeIssuer;\n this.sessionManager = ctx.sessionManager;\n this.eventService = ctx.eventService;\n this.metrics = ctx.metrics;\n this.accessPolicyEvaluator = ctx.accessPolicyEvaluator;\n this.promptLoginMaxAge = ctx.promptLoginMaxAge ?? DEFAULT_PROMPT_LOGIN_MAX_AGE;\n this.mfaFreshnessMaxAge = ctx.mfaFreshnessMaxAge ?? DEFAULT_MFA_FRESHNESS_MAX_AGE;\n this.mfaChallengeProvider = ctx.mfaChallengeProvider;\n }\n\n /**\n * Authorize with validated codeRequest.\n *\n * @param data\n * @param identity\n * @param options\n */\n async authorize(\n data: OAuth2AuthorizationCodeRequest,\n identity: Identity,\n options: OAuth2AuthorizationOptions = {},\n ) : Promise<OAuth2AuthorizationResult> {\n try {\n const result = await this.authorizeInner(data, identity, options);\n\n await this.eventService?.record({\n scope: EventScope.OAUTH2,\n name: EventName.AUTHORIZE,\n refType: EventRefType.CLIENT,\n refId: options.client?.id ?? data.client_id ?? null,\n clientId: options.client?.id ?? data.client_id ?? null,\n sessionId: options.sessionId ?? null,\n actorType: identity.type,\n actorId: identity.data.id,\n actorName: identity.data.name,\n realmId: data.realm_id ?? null,\n data: {\n reason: options.client?.builtIn ? 'autoConsent' : 'consent',\n ...(data.scope ? { scope: data.scope } : {}),\n },\n });\n this.metrics?.recordAuthorize('issued');\n\n return result;\n } catch (e) {\n if (hasInstanceof(e, OAUTH2_ACCESS_DENIED_ERROR_INSTANCE)) {\n await this.eventService?.record({\n scope: EventScope.OAUTH2,\n name: EventName.AUTHORIZE_FAILED,\n refType: EventRefType.CLIENT,\n refId: options.client?.id ?? data.client_id ?? null,\n clientId: options.client?.id ?? data.client_id ?? null,\n sessionId: options.sessionId ?? null,\n actorType: identity.type,\n actorId: identity.data.id,\n actorName: identity.data.name,\n realmId: data.realm_id ?? null,\n data: { reason: 'accessPolicy' },\n });\n this.metrics?.recordAuthorize('denied');\n } else if (hasInstanceof(e, OAUTH2_LOGIN_REQUIRED_ERROR_INSTANCE)) {\n this.metrics?.recordAuthorize('login_required');\n } else if (hasInstanceof(e, OAUTH2_MFA_REQUIRED_ERROR_INSTANCE)) {\n this.metrics?.recordAuthorize('mfa_required');\n } else {\n this.metrics?.recordAuthorize('error');\n }\n\n throw e;\n }\n }\n\n protected async authorizeInner(\n data: OAuth2AuthorizationCodeRequest,\n identity: Identity,\n options: OAuth2AuthorizationOptions = {},\n ) : Promise<OAuth2AuthorizationResult> {\n // OAuth 2.1 posture: only the authorization-code response type is\n // supported — implicit/hybrid (token, id_token, none) were dropped\n // (plan 042 item 3). Defense in depth behind the request validator.\n let responseTypes : string[] = [];\n if (data.response_type) {\n responseTypes = Array.isArray(data.response_type) ?\n data.response_type :\n data.response_type.split(' ');\n }\n\n for (const responseType of responseTypes) {\n if (responseType !== OAuth2AuthorizationResponseType.CODE) {\n throw OAuth2ResponseTypeError.unsupported();\n }\n }\n\n if (!responseTypes.includes(OAuth2AuthorizationResponseType.CODE)) {\n throw OAuth2ResponseTypeError.unsupported();\n }\n\n if (!data.redirect_uri) {\n throw OAuth2GrantError.redirectUriMismatch();\n }\n\n const output : OAuth2AuthorizationResult = {\n redirectUri: data.redirect_uri,\n ...(data.state ? { state: data.state } : {}),\n };\n\n if (!identity) {\n throw OAuth2RequestError.identityInvalid();\n }\n\n // Realm binding: the code-request verifier stamped data.realm_id with the\n // resolved client's realm. The authenticated identity must belong to that\n // same realm — otherwise a lingering session for realm A could silently\n // mint a code/token for realm B's client (confused deputy). The error body\n // deliberately carries no identity data (no realm-enumeration oracle).\n // The comparison reads the scalar realmId column, NOT the realm\n // relation — the relation may simply not be loaded on the resolved\n // identity. An identity without a realmId fails closed the same way —\n // clean login_required, never a TypeError.\n if (\n data.realm_id &&\n identity.data.realmId !== data.realm_id\n ) {\n throw OAuth2LoginRequiredError.realmMismatch();\n }\n\n // Authentication time = the backing session's creation instant (NOT\n // refreshed_at — a token refresh must not reset it). Session-less flows\n // (e.g. HTTP Basic authorize) present live credentials on this request,\n // so the authentication time is \"now\".\n const nowSeconds = Math.floor(Date.now() / 1000);\n let authTime = nowSeconds;\n let session : Session | null = null;\n if (options.sessionId) {\n session = await this.sessionManager.findOneById(options.sessionId);\n if (session && session.createdAt) {\n authTime = Math.floor(new Date(session.createdAt).getTime() / 1000);\n }\n }\n\n // MFA backstop (plan 049) — the authoritative server-side gate; the\n // hosted UI's challenge step is convenience. The proof is session-bound\n // (mfa_at — stamped by the challenge endpoint or the password grant's\n // otp param), so a session-less flow (HTTP Basic) cannot carry one and\n // fails closed while the user holds a confirmed device. A user without\n // a device under mfaRequired is routed to inline enrollment.\n if (this.mfaChallengeProvider && identity.type === IdentityType.USER) {\n // requirement flags only — the interactive challenge material (the\n // webauthn nonce) is issued by the status endpoint, not this backstop.\n const challenge = await this.mfaChallengeProvider.challenge(\n identity.data.id,\n { issueMaterial: false },\n );\n // The local second factor belongs to a local credential. A\n // session established by an external identity provider was\n // authenticated THERE, which is where MFA is configured and\n // enforced for it, so authup does not stack a factor of its own\n // on top and `mfaRequired` does not force local enrollment on\n // those users. The route is opt-in either way: an external\n // identity reaches an existing account only through the\n // bearer-authenticated link flow, since a first login provisions\n // a NEW user (plan 091). A session-less authorize (HTTP Basic) is\n // not external and keeps the gate.\n const externallyAuthenticated = session?.authMethod === SessionAuthMethod.EXTERNAL;\n\n if (!externallyAuthenticated) {\n if (challenge.required && !session?.mfaAt) {\n throw OAuth2MfaRequiredError.challengeRequired();\n }\n\n if (challenge.enrollmentRequired) {\n throw OAuth2MfaRequiredError.enrollmentRequired();\n }\n }\n\n // Step-up (plan 050 stage 3): a requested `acr_values` containing\n // urn:authup:mfa is a TRIGGER (Auth0/Keycloak stance) — the proof\n // must additionally be FRESH (mfaFreshnessMaxAge window, mirroring\n // promptLoginMaxAge's absorb-the-round-trip semantics). Enforced\n // only while the user actually holds a factor — per OIDC Core\n // §5.5.1.1 acr is voluntary, so an unsatisfiable request degrades\n // to the achieved acr instead of bricking the RP.\n //\n // This one DOES apply to an externally authenticated session: the\n // application asked for MFA explicitly, and a local factor the\n // user holds is the only way authup can answer that. Trusting the\n // upstream is the default, not a refusal to prove anything.\n if (challenge.required && data.acr_values) {\n const acrValues = data.acr_values.split(' ');\n if (acrValues.includes(OAuth2AuthenticationContextClass.MFA)) {\n const mfaAtSeconds = session?.mfaAt ?\n Math.floor(new Date(session.mfaAt).getTime() / 1000) :\n null;\n if (mfaAtSeconds === null || nowSeconds - mfaAtSeconds > this.mfaFreshnessMaxAge) {\n throw OAuth2MfaRequiredError.stepUpRequired();\n }\n }\n }\n }\n\n // OIDC §3.1.2.1 prompt=login / max_age freshness (enforced only when\n // requested — a plain authorize never throws here). The hosted page\n // renders the login form for prompt=login; this is the server backstop.\n const prompts = data.prompt ? data.prompt.split(' ') : [];\n if (\n prompts.includes(OAuth2AuthorizationPrompt.LOGIN) &&\n nowSeconds - authTime > this.promptLoginMaxAge\n ) {\n throw OAuth2LoginRequiredError.reauthenticationRequired();\n }\n\n if (\n typeof data.max_age !== 'undefined' &&\n data.max_age !== null\n ) {\n const maxAge = Number(data.max_age);\n if (\n Number.isFinite(maxAge) &&\n nowSeconds - authTime > maxAge\n ) {\n throw OAuth2LoginRequiredError.reauthenticationRequired();\n }\n }\n\n // Application access policy (plan 052) — the last gate before\n // issuance: a denial is only revealed to a fully-authenticated\n // (incl. second-factor) identity. A client carrying a policy id with\n // no wired evaluator denies too (never silently allow a configured\n // gate). The redirect target rides the error only when the\n // redirect_uri was pattern-verified (RFC 6749 §4.1.2.1).\n if (options.client?.accessPolicyId) {\n let allowed = false;\n\n const subject = toIdentityPolicyData(identity);\n if (subject && this.accessPolicyEvaluator) {\n allowed = await this.accessPolicyEvaluator.evaluate(\n options.client.accessPolicyId,\n subject,\n );\n }\n\n if (!allowed) {\n throw OAuth2AccessDeniedError.forClient(\n options.redirectUriVerified && data.redirect_uri ?\n { redirectUri: data.redirect_uri, state: data.state ?? null } :\n undefined,\n );\n }\n }\n\n // The id_token is NOT minted here — the /token exchange mints it after\n // resolving the real backing session, so its `sid` is authoritative\n // (plan 042 item 6). The code carries the authentication instant.\n const codeEntity : OAuth2AuthorizationCode = await this.codeIssuer.issue(\n data,\n identity,\n {\n sessionId: options.sessionId,\n authTime,\n authMethod: session?.authMethod ?? null,\n },\n );\n\n output.authorizationCode = codeEntity.id;\n\n return output;\n }\n}\n"],"mappings":"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"}
|
|
@@ -12,6 +12,14 @@ export type OAuth2AuthorizationState = {
|
|
|
12
12
|
* endpoint, never from client input.
|
|
13
13
|
*/
|
|
14
14
|
link?: OAuth2AuthorizationStateLink;
|
|
15
|
+
/**
|
|
16
|
+
* Ties a federated login to the browser that started it (plan 094). The
|
|
17
|
+
* value is set as a cookie when the login starts and required to match
|
|
18
|
+
* when the provider sends the browser back, so a crafted callback URL
|
|
19
|
+
* opened elsewhere establishes nothing. The state's own ip / user agent
|
|
20
|
+
* cannot do this: both are chosen by whoever mints the state (#3439).
|
|
21
|
+
*/
|
|
22
|
+
browserNonce?: string;
|
|
15
23
|
ip: string;
|
|
16
24
|
userAgent?: string | null;
|
|
17
25
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../../src/core/oauth2/authorization/state/types.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,8BAA8B,EAAE,MAAM,kBAAkB,CAAC;AAEvE,MAAM,MAAM,4BAA4B,GAAG;IACvC,MAAM,EAAE,MAAM,CAAC;IAKf,UAAU,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAAG;IACnC,WAAW,CAAC,EAAE,8BAA8B,CAAC;IAC7C;;;;;OAKG;IACH,IAAI,CAAC,EAAE,4BAA4B,CAAC;IACpC,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAC5B,CAAC;AAEF,MAAM,WAAW,+BAA+B;IAC5C,MAAM,CAAC,IAAI,EAAE,wBAAwB,GAAI,OAAO,CAAC,MAAM,CAAC,CAAC;IAEzD;;;OAGG;IACH,UAAU,CAAC,EAAE,EAAE,MAAM,GAAI,OAAO,CAAC,wBAAwB,GAAG,IAAI,CAAC,CAAC;CACrE;AAED,MAAM,WAAW,gCAAgC;IAC7C,IAAI,CAAC,IAAI,EAAE,wBAAwB,GAAI,OAAO,CAAC,MAAM,CAAC,CAAC;IAEvD,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,wBAAwB,CAAC,GAAG,OAAO,CAAC,wBAAwB,CAAC,CAAC;CACtG"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../../src/core/oauth2/authorization/state/types.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,8BAA8B,EAAE,MAAM,kBAAkB,CAAC;AAEvE,MAAM,MAAM,4BAA4B,GAAG;IACvC,MAAM,EAAE,MAAM,CAAC;IAKf,UAAU,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAAG;IACnC,WAAW,CAAC,EAAE,8BAA8B,CAAC;IAC7C;;;;;OAKG;IACH,IAAI,CAAC,EAAE,4BAA4B,CAAC;IACpC;;;;;;OAMG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAC5B,CAAC;AAEF,MAAM,WAAW,+BAA+B;IAC5C,MAAM,CAAC,IAAI,EAAE,wBAAwB,GAAI,OAAO,CAAC,MAAM,CAAC,CAAC;IAEzD;;;OAGG;IACH,UAAU,CAAC,EAAE,EAAE,MAAM,GAAI,OAAO,CAAC,wBAAwB,GAAG,IAAI,CAAC,CAAC;CACrE;AAED,MAAM,WAAW,gCAAgC;IAC7C,IAAI,CAAC,IAAI,EAAE,wBAAwB,GAAI,OAAO,CAAC,MAAM,CAAC,CAAC;IAEvD,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,wBAAwB,CAAC,GAAG,OAAO,CAAC,wBAAwB,CAAC,CAAC;CACtG"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `events` member a logout token MUST carry
|
|
3
|
+
* (OIDC Back-Channel Logout 1.0, section 2.4).
|
|
4
|
+
*/
|
|
5
|
+
export declare const OAUTH2_BACKCHANNEL_LOGOUT_EVENT = "http://schemas.openid.net/event/backchannel-logout";
|
|
6
|
+
/**
|
|
7
|
+
* Logout token lifetime in seconds. The token is consumed by the RP the
|
|
8
|
+
* moment it arrives, so the lifetime only bounds a replay of a captured one.
|
|
9
|
+
*/
|
|
10
|
+
export declare const OAUTH2_BACKCHANNEL_LOGOUT_MAX_AGE = 120;
|
|
11
|
+
/**
|
|
12
|
+
* Per-delivery timeout in milliseconds. The revoke awaits every delivery, so
|
|
13
|
+
* an unreachable RP must not hold the caller's request open for long.
|
|
14
|
+
*/
|
|
15
|
+
export declare const OAUTH2_BACKCHANNEL_LOGOUT_TIMEOUT = 5000;
|
|
16
|
+
//# sourceMappingURL=constants.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../../src/core/oauth2/backchannel-logout/constants.ts"],"names":[],"mappings":"AAOA;;;GAGG;AACH,eAAO,MAAM,+BAA+B,uDAAuD,CAAC;AAEpG;;;GAGG;AACH,eAAO,MAAM,iCAAiC,MAAM,CAAC;AAErD;;;GAGG;AACH,eAAO,MAAM,iCAAiC,OAAQ,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import "node:path";
|
|
2
|
+
import "node:url";
|
|
3
|
+
import.meta.url;
|
|
4
|
+
//#region src/core/oauth2/backchannel-logout/constants.ts
|
|
5
|
+
/**
|
|
6
|
+
* The `events` member a logout token MUST carry
|
|
7
|
+
* (OIDC Back-Channel Logout 1.0, section 2.4).
|
|
8
|
+
*/ const OAUTH2_BACKCHANNEL_LOGOUT_EVENT = "http://schemas.openid.net/event/backchannel-logout";
|
|
9
|
+
/**
|
|
10
|
+
* Logout token lifetime in seconds. The token is consumed by the RP the
|
|
11
|
+
* moment it arrives, so the lifetime only bounds a replay of a captured one.
|
|
12
|
+
*/ const OAUTH2_BACKCHANNEL_LOGOUT_MAX_AGE = 120;
|
|
13
|
+
/**
|
|
14
|
+
* Per-delivery timeout in milliseconds. The revoke awaits every delivery, so
|
|
15
|
+
* an unreachable RP must not hold the caller's request open for long.
|
|
16
|
+
*/ const OAUTH2_BACKCHANNEL_LOGOUT_TIMEOUT = 5e3;
|
|
17
|
+
//#endregion
|
|
18
|
+
export { OAUTH2_BACKCHANNEL_LOGOUT_EVENT, OAUTH2_BACKCHANNEL_LOGOUT_MAX_AGE, OAUTH2_BACKCHANNEL_LOGOUT_TIMEOUT };
|
|
19
|
+
|
|
20
|
+
//# sourceMappingURL=constants.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.mjs","names":["OAUTH2_BACKCHANNEL_LOGOUT_EVENT","OAUTH2_BACKCHANNEL_LOGOUT_MAX_AGE","OAUTH2_BACKCHANNEL_LOGOUT_TIMEOUT"],"sources":["../../../../src/core/oauth2/backchannel-logout/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 * The `events` member a logout token MUST carry\n * (OIDC Back-Channel Logout 1.0, section 2.4).\n */\nexport const OAUTH2_BACKCHANNEL_LOGOUT_EVENT = 'http://schemas.openid.net/event/backchannel-logout';\n\n/**\n * Logout token lifetime in seconds. The token is consumed by the RP the\n * moment it arrives, so the lifetime only bounds a replay of a captured one.\n */\nexport const OAUTH2_BACKCHANNEL_LOGOUT_MAX_AGE = 120;\n\n/**\n * Per-delivery timeout in milliseconds. The revoke awaits every delivery, so\n * an unreachable RP must not hold the caller's request open for long.\n */\nexport const OAUTH2_BACKCHANNEL_LOGOUT_TIMEOUT = 5_000;\n"],"mappings":";;;;;;;GAWA,MAAaA,kCAAkC;;;;GAM/C,MAAaC,oCAAoC;;;;GAMjD,MAAaC,oCAAoC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/core/oauth2/backchannel-logout/index.ts"],"names":[],"mappings":"AAOA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import "node:path";
|
|
2
|
+
import "node:url";
|
|
3
|
+
import.meta.url;
|
|
4
|
+
import { OAUTH2_BACKCHANNEL_LOGOUT_EVENT, OAUTH2_BACKCHANNEL_LOGOUT_MAX_AGE, OAUTH2_BACKCHANNEL_LOGOUT_TIMEOUT } from "./constants.mjs";
|
|
5
|
+
import { OAuth2BackchannelLogoutNotifier } from "./module.mjs";
|
|
6
|
+
export { OAUTH2_BACKCHANNEL_LOGOUT_EVENT, OAUTH2_BACKCHANNEL_LOGOUT_MAX_AGE, OAUTH2_BACKCHANNEL_LOGOUT_TIMEOUT, OAuth2BackchannelLogoutNotifier };
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { Client, Session } from '@authup/core-kit';
|
|
2
|
+
import type { Logger } from '@authup/server-kit';
|
|
3
|
+
import type { OAuth2TokenPayload } from '@authup/specs';
|
|
4
|
+
import type { ISessionRevokeNotifier } from '../../authentication/session/types.ts';
|
|
5
|
+
import type { IOAuth2ClientRepository } from '../client/types.ts';
|
|
6
|
+
import type { ISessionTokenRepository } from '../session-token/types.ts';
|
|
7
|
+
import type { IOAuth2TokenSigner } from '../token/signer/types.ts';
|
|
8
|
+
import type { OAuth2BackchannelLogoutNotifierContext, OAuth2BackchannelLogoutNotifierOptions } from './types.ts';
|
|
9
|
+
export declare class OAuth2BackchannelLogoutNotifier implements ISessionRevokeNotifier {
|
|
10
|
+
protected signer: IOAuth2TokenSigner;
|
|
11
|
+
protected sessionTokenRepository: ISessionTokenRepository;
|
|
12
|
+
protected clientRepository: IOAuth2ClientRepository;
|
|
13
|
+
protected options: OAuth2BackchannelLogoutNotifierOptions;
|
|
14
|
+
protected logger?: Logger;
|
|
15
|
+
constructor(ctx: OAuth2BackchannelLogoutNotifierContext);
|
|
16
|
+
resolve(session: Session): Promise<Client[]>;
|
|
17
|
+
notify(session: Session, clients: Client[]): Promise<void>;
|
|
18
|
+
protected deliver(session: Session, client: Client): Promise<void>;
|
|
19
|
+
protected buildPayload(session: Session, client: Client): OAuth2TokenPayload;
|
|
20
|
+
/**
|
|
21
|
+
* The same shape `OAuth2BaseTokenIssuer.buildIss` produces for the
|
|
22
|
+
* id_token, so an RP comparing against its discovered issuer matches.
|
|
23
|
+
*/
|
|
24
|
+
protected buildIss(client: Client): string;
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=module.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../../../../src/core/oauth2/backchannel-logout/module.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AACxD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAGxD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,uCAAuC,CAAC;AACpF,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC;AAClE,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,2BAA2B,CAAC;AACzE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAMnE,OAAO,KAAK,EACR,sCAAsC,EACtC,sCAAsC,EACzC,MAAM,YAAY,CAAC;AAEpB,qBAAa,+BAAgC,YAAW,sBAAsB;IAC1E,SAAS,CAAC,MAAM,EAAE,kBAAkB,CAAC;IAErC,SAAS,CAAC,sBAAsB,EAAE,uBAAuB,CAAC;IAE1D,SAAS,CAAC,gBAAgB,EAAE,uBAAuB,CAAC;IAEpD,SAAS,CAAC,OAAO,EAAE,sCAAsC,CAAC;IAE1D,SAAS,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;gBAEd,GAAG,EAAE,sCAAsC;IAQjD,OAAO,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAqB5C,MAAM,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;cAIhD,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA+BxE,SAAS,CAAC,YAAY,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,kBAAkB;IAsB5E;;;OAGG;IACH,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;CAK7C"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import "node:path";
|
|
2
|
+
import "node:url";
|
|
3
|
+
import.meta.url;
|
|
4
|
+
import { OAUTH2_BACKCHANNEL_LOGOUT_EVENT } from "./constants.mjs";
|
|
5
|
+
import { describeError } from "../../../utils/error.mjs";
|
|
6
|
+
import "../../../utils/index.mjs";
|
|
7
|
+
import { OAuth2TokenKind } from "@authup/specs";
|
|
8
|
+
import { randomUUID } from "node:crypto";
|
|
9
|
+
//#region src/core/oauth2/backchannel-logout/module.ts
|
|
10
|
+
var OAuth2BackchannelLogoutNotifier = class {
|
|
11
|
+
signer;
|
|
12
|
+
sessionTokenRepository;
|
|
13
|
+
clientRepository;
|
|
14
|
+
options;
|
|
15
|
+
logger;
|
|
16
|
+
constructor(ctx) {
|
|
17
|
+
this.signer = ctx.signer;
|
|
18
|
+
this.sessionTokenRepository = ctx.sessionTokenRepository;
|
|
19
|
+
this.clientRepository = ctx.clientRepository;
|
|
20
|
+
this.options = ctx.options;
|
|
21
|
+
this.logger = ctx.logger;
|
|
22
|
+
}
|
|
23
|
+
async resolve(session) {
|
|
24
|
+
const tokens = await this.sessionTokenRepository.findBySessionId(session.id);
|
|
25
|
+
const clientIds = /* @__PURE__ */ new Set();
|
|
26
|
+
for (const token of tokens) if (token.clientId) clientIds.add(token.clientId);
|
|
27
|
+
const clients = [];
|
|
28
|
+
for (const clientId of clientIds) {
|
|
29
|
+
const client = await this.clientRepository.findOneByIdOrName(clientId);
|
|
30
|
+
if (client && client.backchannelLogoutUri) clients.push(client);
|
|
31
|
+
}
|
|
32
|
+
return clients;
|
|
33
|
+
}
|
|
34
|
+
async notify(session, clients) {
|
|
35
|
+
await Promise.allSettled(clients.map((client) => this.deliver(session, client)));
|
|
36
|
+
}
|
|
37
|
+
async deliver(session, client) {
|
|
38
|
+
if (!client.backchannelLogoutUri) return;
|
|
39
|
+
try {
|
|
40
|
+
const logoutToken = await this.signer.sign(this.buildPayload(session, client));
|
|
41
|
+
const response = await fetch(client.backchannelLogoutUri, {
|
|
42
|
+
method: "POST",
|
|
43
|
+
headers: { "content-type": "application/x-www-form-urlencoded" },
|
|
44
|
+
body: new URLSearchParams({ logout_token: logoutToken }),
|
|
45
|
+
signal: AbortSignal.timeout(this.options.timeout ?? 5e3),
|
|
46
|
+
redirect: "manual"
|
|
47
|
+
});
|
|
48
|
+
await response.body?.cancel();
|
|
49
|
+
if (!response.ok) this.logger?.warn(`The back-channel logout of client ${client.id} was refused with status ${response.status}.`);
|
|
50
|
+
} catch (e) {
|
|
51
|
+
this.logger?.warn(describeError(e, `The back-channel logout of client ${client.id} failed.`));
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
buildPayload(session, client) {
|
|
55
|
+
const utc = Math.floor(Date.now() / 1e3);
|
|
56
|
+
return {
|
|
57
|
+
kind: OAuth2TokenKind.LOGOUT,
|
|
58
|
+
jti: randomUUID(),
|
|
59
|
+
iss: this.buildIss(client),
|
|
60
|
+
aud: client.id,
|
|
61
|
+
sub: session.sub,
|
|
62
|
+
sid: session.id,
|
|
63
|
+
exp: utc + (this.options.maxAge ?? 120),
|
|
64
|
+
realm_id: client.realmId,
|
|
65
|
+
events: { [OAUTH2_BACKCHANNEL_LOGOUT_EVENT]: {} }
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* The same shape `OAuth2BaseTokenIssuer.buildIss` produces for the
|
|
70
|
+
* id_token, so an RP comparing against its discovered issuer matches.
|
|
71
|
+
*/ buildIss(client) {
|
|
72
|
+
return `${this.options.issuer.replace(/\/+$/, "")}/realms/${client.realm.name}`;
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
//#endregion
|
|
76
|
+
export { OAuth2BackchannelLogoutNotifier };
|
|
77
|
+
|
|
78
|
+
//# sourceMappingURL=module.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"module.mjs","names":["randomUUID","OAuth2TokenKind","describeError","OAUTH2_BACKCHANNEL_LOGOUT_EVENT","OAUTH2_BACKCHANNEL_LOGOUT_MAX_AGE","OAUTH2_BACKCHANNEL_LOGOUT_TIMEOUT","OAuth2BackchannelLogoutNotifier","signer","sessionTokenRepository","clientRepository","options","logger","ctx","resolve","session","tokens","findBySessionId","id","clientIds","Set","token","clientId","add","clients","client","findOneByIdOrName","backchannelLogoutUri","push","notify","Promise","allSettled","map","deliver","logoutToken","sign","buildPayload","response","fetch","method","headers","body","URLSearchParams","logout_token","signal","AbortSignal","timeout","redirect","cancel","ok","warn","status","e","utc","Math","floor","Date","now","kind","LOGOUT","jti","iss","buildIss","aud","sub","sid","exp","maxAge","realm_id","realmId","events","base","issuer","replace","realm","name"],"sources":["../../../../src/core/oauth2/backchannel-logout/module.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 { randomUUID } from 'node:crypto';\nimport type { Client, Session } from '@authup/core-kit';\nimport type { Logger } from '@authup/server-kit';\nimport type { OAuth2TokenPayload } from '@authup/specs';\nimport { OAuth2TokenKind } from '@authup/specs';\nimport { describeError } from '../../../utils/index.ts';\nimport type { ISessionRevokeNotifier } from '../../authentication/session/types.ts';\nimport type { IOAuth2ClientRepository } from '../client/types.ts';\nimport type { ISessionTokenRepository } from '../session-token/types.ts';\nimport type { IOAuth2TokenSigner } from '../token/signer/types.ts';\nimport {\n OAUTH2_BACKCHANNEL_LOGOUT_EVENT,\n OAUTH2_BACKCHANNEL_LOGOUT_MAX_AGE,\n OAUTH2_BACKCHANNEL_LOGOUT_TIMEOUT,\n} from './constants.ts';\nimport type {\n OAuth2BackchannelLogoutNotifierContext,\n OAuth2BackchannelLogoutNotifierOptions,\n} from './types.ts';\n\nexport class OAuth2BackchannelLogoutNotifier implements ISessionRevokeNotifier {\n protected signer: IOAuth2TokenSigner;\n\n protected sessionTokenRepository: ISessionTokenRepository;\n\n protected clientRepository: IOAuth2ClientRepository;\n\n protected options: OAuth2BackchannelLogoutNotifierOptions;\n\n protected logger?: Logger;\n\n constructor(ctx: OAuth2BackchannelLogoutNotifierContext) {\n this.signer = ctx.signer;\n this.sessionTokenRepository = ctx.sessionTokenRepository;\n this.clientRepository = ctx.clientRepository;\n this.options = ctx.options;\n this.logger = ctx.logger;\n }\n\n async resolve(session: Session): Promise<Client[]> {\n const tokens = await this.sessionTokenRepository.findBySessionId(session.id);\n\n const clientIds = new Set<string>();\n for (const token of tokens) {\n if (token.clientId) {\n clientIds.add(token.clientId);\n }\n }\n\n const clients : Client[] = [];\n for (const clientId of clientIds) {\n const client = await this.clientRepository.findOneByIdOrName(clientId);\n if (client && client.backchannelLogoutUri) {\n clients.push(client);\n }\n }\n\n return clients;\n }\n\n async notify(session: Session, clients: Client[]): Promise<void> {\n await Promise.allSettled(clients.map((client) => this.deliver(session, client)));\n }\n\n protected async deliver(session: Session, client: Client): Promise<void> {\n if (!client.backchannelLogoutUri) {\n return;\n }\n\n try {\n const logoutToken = await this.signer.sign(this.buildPayload(session, client));\n\n // `redirect: 'manual'`: a 3xx is the RP's refusal, not an\n // invitation to POST the token somewhere else.\n const response = await fetch(client.backchannelLogoutUri, {\n method: 'POST',\n headers: { 'content-type': 'application/x-www-form-urlencoded' },\n body: new URLSearchParams({ logout_token: logoutToken }),\n signal: AbortSignal.timeout(this.options.timeout ?? OAUTH2_BACKCHANNEL_LOGOUT_TIMEOUT),\n redirect: 'manual',\n });\n\n // The body is never read, and an unread body pins the keep-alive socket.\n await response.body?.cancel();\n\n if (!response.ok) {\n this.logger?.warn(\n `The back-channel logout of client ${client.id} was refused with status ${response.status}.`,\n );\n }\n } catch (e) {\n this.logger?.warn(describeError(e, `The back-channel logout of client ${client.id} failed.`));\n }\n }\n\n protected buildPayload(session: Session, client: Client): OAuth2TokenPayload {\n const utc = Math.floor(Date.now() / 1000);\n\n return {\n kind: OAuth2TokenKind.LOGOUT,\n jti: randomUUID(),\n iss: this.buildIss(client),\n aud: client.id,\n sub: session.sub,\n sid: session.id,\n exp: utc + (this.options.maxAge ?? OAUTH2_BACKCHANNEL_LOGOUT_MAX_AGE),\n // The signer keys on the realm, so the claim rides along (the\n // specification permits additional claims). It is the CLIENT's\n // realm: `iss` is built from `client.realm.name`, so the signing\n // key has to come from the same realm or an RP resolving `kid`\n // through the issuer's JWKS finds nothing. The two differ on the\n // cross-realm password grant (a UUID user with the master client).\n realm_id: client.realmId,\n events: { [OAUTH2_BACKCHANNEL_LOGOUT_EVENT]: {} },\n };\n }\n\n /**\n * The same shape `OAuth2BaseTokenIssuer.buildIss` produces for the\n * id_token, so an RP comparing against its discovered issuer matches.\n */\n protected buildIss(client: Client): string {\n const base = this.options.issuer.replace(/\\/+$/, '');\n\n return `${base}/realms/${client.realm.name}`;\n }\n}\n"],"mappings":";;;;;;;;;AA2BA,IAAaM,kCAAb,MAAaA;CACCC;CAEAC;CAEAC;CAEAC;CAEAC;CAEV,YAAYC,KAA6C;EACrD,KAAKL,SAASK,IAAIL;EAClB,KAAKC,yBAAyBI,IAAIJ;EAClC,KAAKC,mBAAmBG,IAAIH;EAC5B,KAAKC,UAAUE,IAAIF;EACnB,KAAKC,SAASC,IAAID;CACtB;CAEA,MAAME,QAAQC,SAAqC;EAC/C,MAAMC,SAAS,MAAM,KAAKP,uBAAuBQ,gBAAgBF,QAAQG,EAAE;EAE3E,MAAMC,4BAAY,IAAIC,IAAAA;EACtB,KAAK,MAAMC,SAASL,QAChB,IAAIK,MAAMC,UACNH,UAAUI,IAAIF,MAAMC,QAAQ;EAIpC,MAAME,UAAqB,CAAA;EAC3B,KAAK,MAAMF,YAAYH,WAAW;GAC9B,MAAMM,SAAS,MAAM,KAAKf,iBAAiBgB,kBAAkBJ,QAAAA;GAC7D,IAAIG,UAAUA,OAAOE,sBACjBH,QAAQI,KAAKH,MAAAA;EAErB;EAEA,OAAOD;CACX;CAEA,MAAMK,OAAOd,SAAkBS,SAAkC;EAC7D,MAAMM,QAAQC,WAAWP,QAAQQ,KAAKP,WAAW,KAAKQ,QAAQlB,SAASU,MAAAA,CAAAA,CAAAA;CAC3E;CAEA,MAAgBQ,QAAQlB,SAAkBU,QAA+B;EACrE,IAAI,CAACA,OAAOE,sBACR;EAGJ,IAAI;GACA,MAAMO,cAAc,MAAM,KAAK1B,OAAO2B,KAAK,KAAKC,aAAarB,SAASU,MAAAA,CAAAA;GAItE,MAAMY,WAAW,MAAMC,MAAMb,OAAOE,sBAAsB;IACtDY,QAAQ;IACRC,SAAS,EAAE,gBAAgB,oCAAoC;IAC/DC,MAAM,IAAIC,gBAAgB,EAAEC,cAAcT,YAAY,CAAA;IACtDU,QAAQC,YAAYC,QAAQ,KAAKnC,QAAQmC,WAAAA,GAAWxC;IACpDyC,UAAU;GACd,CAAA;GAGA,MAAMV,SAASI,MAAMO,OAAAA;GAErB,IAAI,CAACX,SAASY,IACV,KAAKrC,QAAQsC,KACT,qCAAqCzB,OAAOP,GAAG,2BAA2BmB,SAASc,OAAO,EAAE;EAGxG,SAASC,GAAG;GACR,KAAKxC,QAAQsC,KAAK/C,cAAciD,GAAG,qCAAqC3B,OAAOP,GAAG,SAAS,CAAA;EAC/F;CACJ;CAEUkB,aAAarB,SAAkBU,QAAoC;EACzE,MAAM4B,MAAMC,KAAKC,MAAMC,KAAKC,IAAG,IAAK,GAAA;EAEpC,OAAO;GACHC,MAAMxD,gBAAgByD;GACtBC,KAAK3D,WAAAA;GACL4D,KAAK,KAAKC,SAASrC,MAAAA;GACnBsC,KAAKtC,OAAOP;GACZ8C,KAAKjD,QAAQiD;GACbC,KAAKlD,QAAQG;GACbgD,KAAKb,OAAO,KAAK1C,QAAQwD,UAAAA;GAOzBC,UAAU3C,OAAO4C;GACjBC,QAAQ,GAAGlE,kCAAkC,CAAC,EAAE;EACpD;CACJ;;;;IAMA,SAAmBqB,QAAwB;EAGvC,OAAO,GAFM,KAAKd,QAAQ6D,OAAOC,QAAQ,QAAQ,EAEvCF,EAAK,UAAU9C,OAAOiD,MAAMC;CAC1C;AACJ"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { Logger } from '@authup/server-kit';
|
|
2
|
+
import type { IOAuth2ClientRepository } from '../client/types.ts';
|
|
3
|
+
import type { ISessionTokenRepository } from '../session-token/types.ts';
|
|
4
|
+
import type { IOAuth2TokenSigner } from '../token/signer/types.ts';
|
|
5
|
+
export type OAuth2BackchannelLogoutNotifierOptions = {
|
|
6
|
+
/**
|
|
7
|
+
* The issuer base (publicUrl). The logout token's `iss` is derived from
|
|
8
|
+
* it the way every other token's is: `<issuer>/realms/<realm name>`.
|
|
9
|
+
*/
|
|
10
|
+
issuer: string;
|
|
11
|
+
/**
|
|
12
|
+
* Logout token lifetime in seconds
|
|
13
|
+
* (default: OAUTH2_BACKCHANNEL_LOGOUT_MAX_AGE).
|
|
14
|
+
*/
|
|
15
|
+
maxAge?: number;
|
|
16
|
+
/**
|
|
17
|
+
* Per-delivery timeout in milliseconds
|
|
18
|
+
* (default: OAUTH2_BACKCHANNEL_LOGOUT_TIMEOUT).
|
|
19
|
+
*/
|
|
20
|
+
timeout?: number;
|
|
21
|
+
};
|
|
22
|
+
export type OAuth2BackchannelLogoutNotifierContext = {
|
|
23
|
+
signer: IOAuth2TokenSigner;
|
|
24
|
+
sessionTokenRepository: ISessionTokenRepository;
|
|
25
|
+
clientRepository: IOAuth2ClientRepository;
|
|
26
|
+
options: OAuth2BackchannelLogoutNotifierOptions;
|
|
27
|
+
logger?: Logger;
|
|
28
|
+
};
|
|
29
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/core/oauth2/backchannel-logout/types.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC;AAClE,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,2BAA2B,CAAC;AACzE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAEnE,MAAM,MAAM,sCAAsC,GAAG;IACjD;;;OAGG;IACH,MAAM,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,sCAAsC,GAAG;IACjD,MAAM,EAAE,kBAAkB,CAAC;IAC3B,sBAAsB,EAAE,uBAAuB,CAAC;IAChD,gBAAgB,EAAE,uBAAuB,CAAC;IAC1C,OAAO,EAAE,sCAAsC,CAAC;IAChD,MAAM,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lifetime of a pending console login (plan 088).
|
|
3
|
+
*
|
|
4
|
+
* It covers one redirect to `/authorize` and the return leg, which may
|
|
5
|
+
* traverse an external identity provider, so it is sized like the federated
|
|
6
|
+
* login's pending entry rather than like a session.
|
|
7
|
+
*/
|
|
8
|
+
export declare const CONSOLE_LOGIN_TTL: number;
|
|
9
|
+
/**
|
|
10
|
+
* The cookie carrying the pending login between the server-side kick and the
|
|
11
|
+
* server-side callback that redeems the code.
|
|
12
|
+
*
|
|
13
|
+
* `SameSite=Lax` (the federated-login precedent): the return leg is a
|
|
14
|
+
* top-level navigation that may come back through an external provider, which
|
|
15
|
+
* a `Strict` cookie would not accompany. It holds nothing but the id of a
|
|
16
|
+
* single-use cache entry.
|
|
17
|
+
*/
|
|
18
|
+
export declare const CONSOLE_LOGIN_COOKIE = "authup_console_login";
|
|
19
|
+
//# sourceMappingURL=constants.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../../src/core/oauth2/console-login/constants.ts"],"names":[],"mappings":"AAOA;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB,QAAgB,CAAC;AAE/C;;;;;;;;GAQG;AACH,eAAO,MAAM,oBAAoB,yBAAyB,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import "node:path";
|
|
2
|
+
import "node:url";
|
|
3
|
+
import.meta.url;
|
|
4
|
+
//#region src/core/oauth2/console-login/constants.ts
|
|
5
|
+
/**
|
|
6
|
+
* Lifetime of a pending console login (plan 088).
|
|
7
|
+
*
|
|
8
|
+
* It covers one redirect to `/authorize` and the return leg, which may
|
|
9
|
+
* traverse an external identity provider, so it is sized like the federated
|
|
10
|
+
* login's pending entry rather than like a session.
|
|
11
|
+
*/ const CONSOLE_LOGIN_TTL = 3e5;
|
|
12
|
+
/**
|
|
13
|
+
* The cookie carrying the pending login between the server-side kick and the
|
|
14
|
+
* server-side callback that redeems the code.
|
|
15
|
+
*
|
|
16
|
+
* `SameSite=Lax` (the federated-login precedent): the return leg is a
|
|
17
|
+
* top-level navigation that may come back through an external provider, which
|
|
18
|
+
* a `Strict` cookie would not accompany. It holds nothing but the id of a
|
|
19
|
+
* single-use cache entry.
|
|
20
|
+
*/ const CONSOLE_LOGIN_COOKIE = "authup_console_login";
|
|
21
|
+
//#endregion
|
|
22
|
+
export { CONSOLE_LOGIN_COOKIE, CONSOLE_LOGIN_TTL };
|
|
23
|
+
|
|
24
|
+
//# sourceMappingURL=constants.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.mjs","names":["CONSOLE_LOGIN_TTL","CONSOLE_LOGIN_COOKIE"],"sources":["../../../../src/core/oauth2/console-login/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 console login (plan 088).\n *\n * It covers one redirect to `/authorize` and the return leg, which may\n * traverse an external identity provider, so it is sized like the federated\n * login's pending entry rather than like a session.\n */\nexport const CONSOLE_LOGIN_TTL = 1000 * 60 * 5;\n\n/**\n * The cookie carrying the pending login between the server-side kick and the\n * server-side callback that redeems the code.\n *\n * `SameSite=Lax` (the federated-login precedent): the return leg is a\n * top-level navigation that may come back through an external provider, which\n * a `Strict` cookie would not accompany. It holds nothing but the id of a\n * single-use cache entry.\n */\nexport const CONSOLE_LOGIN_COOKIE = 'authup_console_login';\n"],"mappings":";;;;;;;;;;GAcA,MAAaA,oBAAoB;;;;;;;;;GAWjC,MAAaC,uBAAuB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/core/oauth2/console-login/index.ts"],"names":[],"mappings":"AAOA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a pending console login holds while the browser is away at
|
|
3
|
+
* `/authorize` (plan 088). Only what the redemption needs, and nothing a
|
|
4
|
+
* leaked entry would make redeemable on its own: the browser additionally
|
|
5
|
+
* has to present the login cookie naming it.
|
|
6
|
+
*/
|
|
7
|
+
export type ConsoleLoginPending = {
|
|
8
|
+
/**
|
|
9
|
+
* The `state` the authorize request carried. Validated against the
|
|
10
|
+
* callback's own `state` BEFORE the entry is consumed, so a second tab's
|
|
11
|
+
* callback cannot burn the first tab's login.
|
|
12
|
+
*/
|
|
13
|
+
state: string;
|
|
14
|
+
/**
|
|
15
|
+
* The PKCE verifier the token exchange presents. The console client is
|
|
16
|
+
* public, so a code cannot be redeemed without it.
|
|
17
|
+
*/
|
|
18
|
+
codeVerifier: string;
|
|
19
|
+
/**
|
|
20
|
+
* The `redirect_uri` the authorize request carried. RFC 6749 §4.1.3
|
|
21
|
+
* requires the token request to repeat it verbatim, and the verifier
|
|
22
|
+
* compares the raw stored string, so it is replayed from here rather than
|
|
23
|
+
* rebuilt from the callback URL.
|
|
24
|
+
*/
|
|
25
|
+
redirectUri: string;
|
|
26
|
+
/**
|
|
27
|
+
* The realm the login was started in. Required: the console client is
|
|
28
|
+
* identified by NAME, and a name-identified client needs a realm hint at
|
|
29
|
+
* `/authorize` and at `/token` alike (client names are unique per realm,
|
|
30
|
+
* and every realm carries the same-named system clients).
|
|
31
|
+
*/
|
|
32
|
+
realmId: string;
|
|
33
|
+
};
|
|
34
|
+
export interface IConsoleLoginStore {
|
|
35
|
+
/**
|
|
36
|
+
* @returns the id of the pending login
|
|
37
|
+
*/
|
|
38
|
+
save(data: ConsoleLoginPending): Promise<string>;
|
|
39
|
+
/**
|
|
40
|
+
* Reads WITHOUT dropping, so the callback can check `state` before it
|
|
41
|
+
* spends anything. One browser holds one login cookie, so a second tab's
|
|
42
|
+
* kick overwrites the first tab's id: consuming before the check would let
|
|
43
|
+
* tab A's stale callback burn tab B's live login. A read alone redeems
|
|
44
|
+
* nothing: the entry still has to be consumed, and the code still has to
|
|
45
|
+
* match the verifier it holds.
|
|
46
|
+
*/
|
|
47
|
+
find(id: string): Promise<ConsoleLoginPending | null>;
|
|
48
|
+
/**
|
|
49
|
+
* Reads and DROPS it. Single use: one pending login redeems once.
|
|
50
|
+
*/
|
|
51
|
+
consume(id: string): Promise<ConsoleLoginPending | null>;
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/core/oauth2/console-login/types.ts"],"names":[],"mappings":"AAOA;;;;;GAKG;AACH,MAAM,MAAM,mBAAmB,GAAG;IAC9B;;;;OAIG;IACH,KAAK,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,YAAY,EAAE,MAAM,CAAC;IACrB;;;;;OAKG;IACH,WAAW,EAAE,MAAM,CAAC;IACpB;;;;;OAKG;IACH,OAAO,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,WAAW,kBAAkB;IAC/B;;OAEG;IACH,IAAI,CAAC,IAAI,EAAE,mBAAmB,GAAI,OAAO,CAAC,MAAM,CAAC,CAAC;IAElD;;;;;;;OAOG;IACH,IAAI,CAAC,EAAE,EAAE,MAAM,GAAI,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAAC,CAAC;IAEvD;;OAEG;IACH,OAAO,CAAC,EAAE,EAAE,MAAM,GAAI,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAAC,CAAC;CAC7D"}
|
|
@@ -53,7 +53,7 @@ var OAuth2EndSessionService = class {
|
|
|
53
53
|
}
|
|
54
54
|
if (hintVerified && data.client_id) {
|
|
55
55
|
const expected = isUUID(data.client_id) ? data.client_id : client?.id;
|
|
56
|
-
if (audiences.length === 0 || !
|
|
56
|
+
if (!expected || audiences.length === 0 || !audiences.includes(expected)) {
|
|
57
57
|
hintVerified = false;
|
|
58
58
|
sub = void 0;
|
|
59
59
|
subKind = void 0;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service.mjs","names":["isSimpleURLMatch","isUUID","EventName","EventRefType","EventScope","OAuth2TokenKind","OAuth2EndSessionService","tokenVerifier","sessionManager","clientRepository","realmRepository","eventService","hintGracePeriod","ctx","verify","data","hintVerified","sub","subKind","sessionId","hintRealmId","audiences","id_token_hint","payload","ignoreExpiry","skipActiveCheck","kind","ID_TOKEN","isWithinHintGraceWindow","sub_kind","sid","session_id","undefined","realm_id","aud","Array","isArray","filter","entry","clientId","client_id","length","client","realmKey","realm_name","realm","resolve","findOneByIdOrName","id","expected","includes","clientName","redirectUri","name","post_logout_redirect_uri","isValidPostLogoutRedirect","postLogoutRedirectUri","state","revoke","session","findOneById","record","scope","OAUTH2","LOGOUT","refType","SESSION","refId","actorType","actorId","realmId","exp","nowSeconds","Math","floor","Date","now","registered","candidate","parsed","URL","protocol","username","password","split"],"sources":["../../../../src/core/oauth2/end-session/service.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 { isSimpleURLMatch, isUUID } from '@authup/kit';\nimport type { Client, IdentityType } from '@authup/core-kit';\nimport { EventName, EventRefType, EventScope } from '@authup/core-kit';\nimport type { OAuth2TokenPayload } from '@authup/specs';\nimport { OAuth2TokenKind } from '@authup/specs';\nimport type { IEventService, IRealmRepository } from '../../entities/index.ts';\nimport type { ISessionManager } from '../../authentication/index.ts';\nimport type { IOAuth2ClientRepository } from '../client/index.ts';\nimport type { IOAuth2TokenVerifier } from '../token/index.ts';\nimport type {\n IOAuth2EndSessionService,\n OAuth2EndSessionRequest,\n OAuth2EndSessionResult,\n OAuth2EndSessionServiceContext,\n} from './types.ts';\n\nexport class OAuth2EndSessionService implements IOAuth2EndSessionService {\n protected tokenVerifier: IOAuth2TokenVerifier;\n\n protected sessionManager: ISessionManager;\n\n protected clientRepository: IOAuth2ClientRepository;\n\n protected realmRepository: IRealmRepository;\n\n protected eventService?: IEventService;\n\n protected hintGracePeriod: number;\n\n constructor(ctx: OAuth2EndSessionServiceContext) {\n this.tokenVerifier = ctx.tokenVerifier;\n this.sessionManager = ctx.sessionManager;\n this.clientRepository = ctx.clientRepository;\n this.realmRepository = ctx.realmRepository;\n this.eventService = ctx.eventService;\n this.hintGracePeriod = ctx.hintGracePeriod ?? 0;\n }\n\n async verify(data: OAuth2EndSessionRequest): Promise<OAuth2EndSessionResult> {\n let hintVerified = false;\n let sub: string | undefined;\n let subKind: string | undefined;\n let sessionId: string | undefined;\n let hintRealmId: string | undefined;\n let audiences: string[] = [];\n\n if (data.id_token_hint) {\n try {\n // Signature + kind are the anchors; exp is skipped (a logout hint\n // is routinely expired) and the cache blocklist is irrelevant.\n const payload = await this.tokenVerifier.verify(data.id_token_hint, {\n ignoreExpiry: true,\n skipActiveCheck: true,\n });\n\n // MUST be an id_token — access/refresh tokens also carry\n // session_id, so accepting them would let a leaked access token\n // act as a logout weapon.\n if (payload.kind === OAuth2TokenKind.ID_TOKEN && this.isWithinHintGraceWindow(payload)) {\n hintVerified = true;\n sub = payload.sub;\n subKind = payload.sub_kind;\n sessionId = payload.sid ?? payload.session_id ?? undefined;\n hintRealmId = payload.realm_id ?? undefined;\n // aud may be a single string or an array (JWT spec).\n const { aud } = payload;\n if (Array.isArray(aud)) {\n audiences = aud.filter((entry): entry is string => typeof entry === 'string');\n } else if (typeof aud === 'string') {\n audiences = [aud];\n }\n }\n } catch {\n // forged / unverifiable hint → stays unverified (no revoke)\n }\n }\n\n // Resolve a single client for the aud cross-check and redirect\n // validation: the request's client_id, else the hint's sole audience\n // (ambiguous for a multi-aud hint).\n const clientId = data.client_id ?? (audiences.length === 1 ? audiences[0] : undefined);\n\n let client: Client | null = null;\n if (clientId) {\n // Scope a name-identified client to the request's realm hint; a\n // VERIFIED hint's own realm claim serves as fallback (claims from an\n // unverified hint are never trusted). No master fallback here\n // (unlike /token): a bogus hint must NOT silently resolve a\n // same-named client in master → null realm.\n const realmKey = data.realm_id ?? data.realm_name ?? (hintVerified ? hintRealmId : undefined);\n const realm = await this.realmRepository.resolve(realmKey, false);\n\n // Fail closed instead of dropping the realm predicate: a supplied\n // realm key that does not resolve never degrades to an unscoped\n // lookup, and a NAME-form client_id without any realm key is\n // ambiguous (client names are only unique per realm, and every\n // realm carries the same-named system clients — same rule as the\n // /authorize verifier). A UUID is globally unique and needs no\n // scope; the sole-aud-derived clientId is always a UUID.\n if (realm) {\n client = await this.clientRepository.findOneByIdOrName(clientId, realm.id);\n } else if (!realmKey && isUUID(clientId)) {\n client = await this.clientRepository.findOneByIdOrName(clientId);\n }\n }\n\n // aud/client_id cross-check: when the request supplies a client_id on a\n // verified hint, it MUST denote one of the hint's audiences. The aud is\n // the client UUID, so a name-form client_id is compared via its resolved\n // client's id. Fail closed: an aud-less hint, or a name that did not\n // resolve, counts as unverified.\n if (hintVerified && data.client_id) {\n const expected = isUUID(data.client_id) ? data.client_id : client?.id;\n if (audiences.length === 0 || !expected || !audiences.includes(expected)) {\n hintVerified = false;\n sub = undefined;\n subKind = undefined;\n sessionId = undefined;\n }\n }\n\n let clientName: string | undefined;\n let redirectUri: string | undefined;\n\n // Redirect validation is independent of hint verification — the\n // click-gated confirm page (unverified hint / hint-less request) still\n // honors a registered post-logout redirect.\n if (client) {\n clientName = client.name;\n if (\n data.post_logout_redirect_uri &&\n this.isValidPostLogoutRedirect(client.postLogoutRedirectUri, data.post_logout_redirect_uri)\n ) {\n redirectUri = data.post_logout_redirect_uri;\n }\n }\n\n return {\n hintVerified,\n ...(hintVerified ? {\n sub,\n subKind,\n sessionId,\n } : {}),\n ...(clientId ? { clientId } : {}),\n ...(clientName ? { clientName } : {}),\n ...(redirectUri ? { redirectUri, ...(data.state ? { state: data.state } : {}) } : {}),\n };\n }\n\n async revoke(sessionId: string, sub: string, subKind: string): Promise<boolean> {\n const session = await this.sessionManager.findOneById(sessionId);\n if (!session) {\n return false;\n }\n\n // Never revoke a session that does not belong to the hint's subject.\n if (session.sub !== sub || session.subKind !== subKind) {\n return false;\n }\n\n await this.sessionManager.revoke(sessionId);\n\n await this.eventService?.record({\n scope: EventScope.OAUTH2,\n name: EventName.LOGOUT,\n refType: EventRefType.SESSION,\n refId: sessionId,\n sessionId,\n actorType: session.subKind as `${IdentityType}`,\n actorId: session.sub,\n realmId: session.realmId,\n });\n\n return true;\n }\n\n /**\n * With a positive `hintGracePeriod`, an expired hint is honored only within\n * the window past `exp` — beyond it a leaked id_token stops being a\n * replayable remote logout (the hint counts as unverified; the click-gated\n * confirm page still works). 0 keeps spec/Keycloak parity: any expired hint.\n */\n protected isWithinHintGraceWindow(payload: OAuth2TokenPayload): boolean {\n if (this.hintGracePeriod <= 0) {\n return true;\n }\n\n // a bounded window without an exp claim to judge against fails closed\n if (typeof payload.exp !== 'number') {\n return false;\n }\n\n const nowSeconds = Math.floor(Date.now() / 1000);\n return nowSeconds - payload.exp <= this.hintGracePeriod;\n }\n\n /**\n * A post-logout redirect is honored only when it is an absolute http(s) URL\n * that matches a registered client redirect pattern (defense against open\n * redirects to attacker-controlled URLs).\n */\n protected isValidPostLogoutRedirect(\n registered: string | null | undefined,\n candidate: string,\n ): boolean {\n let parsed: URL;\n try {\n parsed = new URL(candidate);\n } catch {\n return false;\n }\n\n if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {\n return false;\n }\n\n // The matcher canonicalizes the candidate (userinfo dropped) while the\n // redirect is built from the raw value, so a credential blob would\n // ride the Location header (#3455).\n if (parsed.username || parsed.password) {\n return false;\n }\n\n if (!registered) {\n return false;\n }\n\n // isSimpleURLMatch, never isSimpleMatch: matched against the raw\n // string, a `*` in a registered pattern's host absorbs a `?`, `#` or\n // `\\`, which would turn this endpoint into a server-issued open\n // redirect carrying `state`.\n return isSimpleURLMatch(candidate, registered.split(','));\n }\n}\n"],"mappings":";;;;;;;AAuBA,IAAaM,0BAAb,MAAaA;CACCC;CAEAC;CAEAC;CAEAC;CAEAC;CAEAC;CAEV,YAAYC,KAAqC;EAC7C,KAAKN,gBAAgBM,IAAIN;EACzB,KAAKC,iBAAiBK,IAAIL;EAC1B,KAAKC,mBAAmBI,IAAIJ;EAC5B,KAAKC,kBAAkBG,IAAIH;EAC3B,KAAKC,eAAeE,IAAIF;EACxB,KAAKC,kBAAkBC,IAAID,mBAAmB;CAClD;CAEA,MAAME,OAAOC,MAAgE;EACzE,IAAIC,eAAe;EACnB,IAAIC;EACJ,IAAIC;EACJ,IAAIC;EACJ,IAAIC;EACJ,IAAIC,YAAsB,CAAA;EAE1B,IAAIN,KAAKO,eACL,IAAI;GAGA,MAAMC,UAAU,MAAM,KAAKhB,cAAcO,OAAOC,KAAKO,eAAe;IAChEE,cAAc;IACdC,iBAAiB;GACrB,CAAA;GAKA,IAAIF,QAAQG,SAASrB,gBAAgBsB,YAAY,KAAKC,wBAAwBL,OAAAA,GAAU;IACpFP,eAAe;IACfC,MAAMM,QAAQN;IACdC,UAAUK,QAAQM;IAClBV,YAAYI,QAAQO,OAAOP,QAAQQ,cAAcC,KAAAA;IACjDZ,cAAcG,QAAQU,YAAYD,KAAAA;IAElC,MAAM,EAAEE,QAAQX;IAChB,IAAIY,MAAMC,QAAQF,GAAAA,GACdb,YAAYa,IAAIG,QAAQC,UAA2B,OAAOA,UAAU,QAAA;SACjE,IAAI,OAAOJ,QAAQ,UACtBb,YAAY,CAACa,GAAI;GAEzB;EACJ,QAAQ,CAER;EAMJ,MAAMK,WAAWxB,KAAKyB,cAAcnB,UAAUoB,WAAW,IAAIpB,UAAU,KAAKW,KAAAA;EAE5E,IAAIU,SAAwB;EAC5B,IAAIH,UAAU;GAMV,MAAMI,WAAW5B,KAAKkB,YAAYlB,KAAK6B,eAAe5B,eAAeI,cAAcY,KAAAA;GACnF,MAAMa,QAAQ,MAAM,KAAKnC,gBAAgBoC,QAAQH,UAAU,KAAA;GAS3D,IAAIE,OACAH,SAAS,MAAM,KAAKjC,iBAAiBsC,kBAAkBR,UAAUM,MAAMG,EAAE;QACtE,IAAI,CAACL,YAAY1C,OAAOsC,QAAAA,GAC3BG,SAAS,MAAM,KAAKjC,iBAAiBsC,kBAAkBR,QAAAA;EAE/D;EAOA,IAAIvB,gBAAgBD,KAAKyB,WAAW;GAChC,MAAMS,WAAWhD,OAAOc,KAAKyB,SAAS,IAAIzB,KAAKyB,YAAYE,QAAQM;GACnE,IAAI3B,UAAUoB,WAAW,KAAK,CAACQ,YAAY,CAAC5B,UAAU6B,SAASD,QAAAA,GAAW;IACtEjC,eAAe;IACfC,MAAMe,KAAAA;IACNd,UAAUc,KAAAA;IACVb,YAAYa,KAAAA;GAChB;EACJ;EAEA,IAAImB;EACJ,IAAIC;EAKJ,IAAIV,QAAQ;GACRS,aAAaT,OAAOW;GACpB,IACItC,KAAKuC,4BACL,KAAKC,0BAA0Bb,OAAOc,uBAAuBzC,KAAKuC,wBAAwB,GAE1FF,cAAcrC,KAAKuC;EAE3B;EAEA,OAAO;GACHtC;GACA,GAAIA,eAAe;IACfC;IACAC;IACAC;GACJ,IAAI,CAAC;GACL,GAAIoB,WAAW,EAAEA,SAAS,IAAI,CAAC;GAC/B,GAAIY,aAAa,EAAEA,WAAW,IAAI,CAAC;GACnC,GAAIC,cAAc;IAAEA;IAAa,GAAIrC,KAAK0C,QAAQ,EAAEA,OAAO1C,KAAK0C,MAAM,IAAI,CAAC;GAAG,IAAI,CAAC;EACvF;CACJ;CAEA,MAAMC,OAAOvC,WAAmBF,KAAaC,SAAmC;EAC5E,MAAMyC,UAAU,MAAM,KAAKnD,eAAeoD,YAAYzC,SAAAA;EACtD,IAAI,CAACwC,SACD,OAAO;EAIX,IAAIA,QAAQ1C,QAAQA,OAAO0C,QAAQzC,YAAYA,SAC3C,OAAO;EAGX,MAAM,KAAKV,eAAekD,OAAOvC,SAAAA;EAEjC,MAAM,KAAKR,cAAckD,OAAO;GAC5BC,OAAO1D,WAAW2D;GAClBV,MAAMnD,UAAU8D;GAChBC,SAAS9D,aAAa+D;GACtBC,OAAOhD;GACPA;GACAiD,WAAWT,QAAQzC;GACnBmD,SAASV,QAAQ1C;GACjBqD,SAASX,QAAQW;EACrB,CAAA;EAEA,OAAO;CACX;;;;;;IAQA,wBAAkC/C,SAAsC;EACpE,IAAI,KAAKX,mBAAmB,GACxB,OAAO;EAIX,IAAI,OAAOW,QAAQgD,QAAQ,UACvB,OAAO;EAIX,OADmBE,KAAKC,MAAMC,KAAKC,IAAG,IAAK,GACpCJ,IAAajD,QAAQgD,OAAO,KAAK3D;CAC5C;;;;;IAOA,0BACIiE,YACAC,WACO;EACP,IAAIC;EACJ,IAAI;GACAA,SAAS,IAAIC,IAAIF,SAAAA;EACrB,QAAQ;GACJ,OAAO;EACX;EAEA,IAAIC,OAAOE,aAAa,WAAWF,OAAOE,aAAa,UACnD,OAAO;EAMX,IAAIF,OAAOG,YAAYH,OAAOI,UAC1B,OAAO;EAGX,IAAI,CAACN,YACD,OAAO;EAOX,OAAO7E,iBAAiB8E,WAAWD,WAAWO,MAAM,GAAA,CAAA;CACxD;AACJ"}
|
|
1
|
+
{"version":3,"file":"service.mjs","names":["isSimpleURLMatch","isUUID","EventName","EventRefType","EventScope","OAuth2TokenKind","OAuth2EndSessionService","tokenVerifier","sessionManager","clientRepository","realmRepository","eventService","hintGracePeriod","ctx","verify","data","hintVerified","sub","subKind","sessionId","hintRealmId","audiences","id_token_hint","payload","ignoreExpiry","skipActiveCheck","kind","ID_TOKEN","isWithinHintGraceWindow","sub_kind","sid","session_id","undefined","realm_id","aud","Array","isArray","filter","entry","clientId","client_id","length","client","realmKey","realm_name","realm","resolve","findOneByIdOrName","id","expected","includes","clientName","redirectUri","name","post_logout_redirect_uri","isValidPostLogoutRedirect","postLogoutRedirectUri","state","revoke","session","findOneById","record","scope","OAUTH2","LOGOUT","refType","SESSION","refId","actorType","actorId","realmId","exp","nowSeconds","Math","floor","Date","now","registered","candidate","parsed","URL","protocol","username","password","split"],"sources":["../../../../src/core/oauth2/end-session/service.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 { isSimpleURLMatch, isUUID } from '@authup/kit';\nimport type { Client, IdentityType } from '@authup/core-kit';\nimport { EventName, EventRefType, EventScope } from '@authup/core-kit';\nimport type { OAuth2TokenPayload } from '@authup/specs';\nimport { OAuth2TokenKind } from '@authup/specs';\nimport type { IEventService, IRealmRepository } from '../../entities/index.ts';\nimport type { ISessionManager } from '../../authentication/index.ts';\nimport type { IOAuth2ClientRepository } from '../client/index.ts';\nimport type { IOAuth2TokenVerifier } from '../token/index.ts';\nimport type {\n IOAuth2EndSessionService,\n OAuth2EndSessionRequest,\n OAuth2EndSessionResult,\n OAuth2EndSessionServiceContext,\n} from './types.ts';\n\nexport class OAuth2EndSessionService implements IOAuth2EndSessionService {\n protected tokenVerifier: IOAuth2TokenVerifier;\n\n protected sessionManager: ISessionManager;\n\n protected clientRepository: IOAuth2ClientRepository;\n\n protected realmRepository: IRealmRepository;\n\n protected eventService?: IEventService;\n\n protected hintGracePeriod: number;\n\n constructor(ctx: OAuth2EndSessionServiceContext) {\n this.tokenVerifier = ctx.tokenVerifier;\n this.sessionManager = ctx.sessionManager;\n this.clientRepository = ctx.clientRepository;\n this.realmRepository = ctx.realmRepository;\n this.eventService = ctx.eventService;\n this.hintGracePeriod = ctx.hintGracePeriod ?? 0;\n }\n\n async verify(data: OAuth2EndSessionRequest): Promise<OAuth2EndSessionResult> {\n let hintVerified = false;\n let sub: string | undefined;\n let subKind: string | undefined;\n let sessionId: string | undefined;\n let hintRealmId: string | undefined;\n let audiences: string[] = [];\n\n if (data.id_token_hint) {\n try {\n // Signature + kind are the anchors; exp is skipped (a logout hint\n // is routinely expired) and the cache blocklist is irrelevant.\n const payload = await this.tokenVerifier.verify(data.id_token_hint, {\n ignoreExpiry: true,\n skipActiveCheck: true,\n });\n\n // MUST be an id_token — access/refresh tokens also carry\n // session_id, so accepting them would let a leaked access token\n // act as a logout weapon.\n if (payload.kind === OAuth2TokenKind.ID_TOKEN && this.isWithinHintGraceWindow(payload)) {\n hintVerified = true;\n sub = payload.sub;\n subKind = payload.sub_kind;\n sessionId = payload.sid ?? payload.session_id ?? undefined;\n hintRealmId = payload.realm_id ?? undefined;\n // aud may be a single string or an array (JWT spec).\n const { aud } = payload;\n if (Array.isArray(aud)) {\n audiences = aud.filter((entry): entry is string => typeof entry === 'string');\n } else if (typeof aud === 'string') {\n audiences = [aud];\n }\n }\n } catch {\n // forged / unverifiable hint → stays unverified (no revoke)\n }\n }\n\n // Resolve a single client for the aud cross-check and redirect\n // validation: the request's client_id, else the hint's sole audience\n // (ambiguous for a multi-aud hint).\n const clientId = data.client_id ?? (audiences.length === 1 ? audiences[0] : undefined);\n\n let client: Client | null = null;\n if (clientId) {\n // Scope a name-identified client to the request's realm hint; a\n // VERIFIED hint's own realm claim serves as fallback (claims from an\n // unverified hint are never trusted). No master fallback here\n // (unlike /token): a bogus hint must NOT silently resolve a\n // same-named client in master → null realm.\n const realmKey = data.realm_id ?? data.realm_name ?? (hintVerified ? hintRealmId : undefined);\n const realm = await this.realmRepository.resolve(realmKey, false);\n\n // Fail closed instead of dropping the realm predicate: a supplied\n // realm key that does not resolve never degrades to an unscoped\n // lookup, and a NAME-form client_id without any realm key is\n // ambiguous (client names are only unique per realm, and every\n // realm carries the same-named system clients — same rule as the\n // /authorize verifier). A UUID is globally unique and needs no\n // scope; the sole-aud-derived clientId is always a UUID.\n if (realm) {\n client = await this.clientRepository.findOneByIdOrName(clientId, realm.id);\n } else if (!realmKey && isUUID(clientId)) {\n client = await this.clientRepository.findOneByIdOrName(clientId);\n }\n }\n\n // aud/client_id cross-check: when the request supplies a client_id on a\n // verified hint, it MUST denote one of the hint's audiences. The aud is\n // the client UUID, so a name-form client_id is compared via its resolved\n // client's id. Fail closed: an aud-less hint, or a name that did not\n // resolve, counts as unverified.\n if (hintVerified && data.client_id) {\n const expected = isUUID(data.client_id) ? data.client_id : client?.id;\n if (!expected || audiences.length === 0 || !audiences.includes(expected)) {\n hintVerified = false;\n sub = undefined;\n subKind = undefined;\n sessionId = undefined;\n }\n }\n\n let clientName: string | undefined;\n let redirectUri: string | undefined;\n\n // Redirect validation is independent of hint verification — the\n // click-gated confirm page (unverified hint / hint-less request) still\n // honors a registered post-logout redirect.\n if (client) {\n clientName = client.name;\n if (\n data.post_logout_redirect_uri &&\n this.isValidPostLogoutRedirect(client.postLogoutRedirectUri, data.post_logout_redirect_uri)\n ) {\n redirectUri = data.post_logout_redirect_uri;\n }\n }\n\n return {\n hintVerified,\n ...(hintVerified ? {\n sub,\n subKind,\n sessionId,\n } : {}),\n ...(clientId ? { clientId } : {}),\n ...(clientName ? { clientName } : {}),\n ...(redirectUri ? { redirectUri, ...(data.state ? { state: data.state } : {}) } : {}),\n };\n }\n\n async revoke(sessionId: string, sub: string, subKind: string): Promise<boolean> {\n const session = await this.sessionManager.findOneById(sessionId);\n if (!session) {\n return false;\n }\n\n // Never revoke a session that does not belong to the hint's subject.\n if (session.sub !== sub || session.subKind !== subKind) {\n return false;\n }\n\n await this.sessionManager.revoke(sessionId);\n\n await this.eventService?.record({\n scope: EventScope.OAUTH2,\n name: EventName.LOGOUT,\n refType: EventRefType.SESSION,\n refId: sessionId,\n sessionId,\n actorType: session.subKind as `${IdentityType}`,\n actorId: session.sub,\n realmId: session.realmId,\n });\n\n return true;\n }\n\n /**\n * With a positive `hintGracePeriod`, an expired hint is honored only within\n * the window past `exp` — beyond it a leaked id_token stops being a\n * replayable remote logout (the hint counts as unverified; the click-gated\n * confirm page still works). 0 keeps spec/Keycloak parity: any expired hint.\n */\n protected isWithinHintGraceWindow(payload: OAuth2TokenPayload): boolean {\n if (this.hintGracePeriod <= 0) {\n return true;\n }\n\n // a bounded window without an exp claim to judge against fails closed\n if (typeof payload.exp !== 'number') {\n return false;\n }\n\n const nowSeconds = Math.floor(Date.now() / 1000);\n return nowSeconds - payload.exp <= this.hintGracePeriod;\n }\n\n /**\n * A post-logout redirect is honored only when it is an absolute http(s) URL\n * that matches a registered client redirect pattern (defense against open\n * redirects to attacker-controlled URLs).\n */\n protected isValidPostLogoutRedirect(\n registered: string | null | undefined,\n candidate: string,\n ): boolean {\n let parsed: URL;\n try {\n parsed = new URL(candidate);\n } catch {\n return false;\n }\n\n if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {\n return false;\n }\n\n // The matcher canonicalizes the candidate (userinfo dropped) while the\n // redirect is built from the raw value, so a credential blob would\n // ride the Location header (#3455).\n if (parsed.username || parsed.password) {\n return false;\n }\n\n if (!registered) {\n return false;\n }\n\n // isSimpleURLMatch, never isSimpleMatch: matched against the raw\n // string, a `*` in a registered pattern's host absorbs a `?`, `#` or\n // `\\`, which would turn this endpoint into a server-issued open\n // redirect carrying `state`.\n return isSimpleURLMatch(candidate, registered.split(','));\n }\n}\n"],"mappings":"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"}
|