@authup/server-core 1.0.0-beta.61 → 1.0.0-beta.63
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapters/database/domains/client-scope/entity.d.ts.map +1 -1
- package/dist/adapters/database/domains/client-scope/entity.mjs +16 -8
- package/dist/adapters/database/domains/client-scope/entity.mjs.map +1 -1
- package/dist/adapters/database/domains/identity-provider-account/entity.d.ts.map +1 -1
- package/dist/adapters/database/domains/identity-provider-account/entity.mjs +1 -1
- package/dist/adapters/database/domains/identity-provider-account/entity.mjs.map +1 -1
- package/dist/adapters/database/domains/identity-provider-attribute/subscriber.d.ts +8 -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/migrations/mysql/1786631686318-SortIndexesAndAccountUniqueness.d.ts +50 -0
- package/dist/adapters/database/migrations/mysql/1786631686318-SortIndexesAndAccountUniqueness.d.ts.map +1 -0
- package/dist/adapters/database/migrations/mysql/1786631686318-SortIndexesAndAccountUniqueness.mjs +86 -0
- package/dist/adapters/database/migrations/mysql/1786631686318-SortIndexesAndAccountUniqueness.mjs.map +1 -0
- package/dist/adapters/database/migrations/postgres/1786631686318-SortIndexesAndAccountUniqueness.d.ts +42 -0
- package/dist/adapters/database/migrations/postgres/1786631686318-SortIndexesAndAccountUniqueness.d.ts.map +1 -0
- package/dist/adapters/database/migrations/postgres/1786631686318-SortIndexesAndAccountUniqueness.mjs +80 -0
- package/dist/adapters/database/migrations/postgres/1786631686318-SortIndexesAndAccountUniqueness.mjs.map +1 -0
- 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/adapters/oauth2/grant-types/utils/credentials.mjs +1 -1
- package/dist/adapters/http/adapters/oauth2/grant-types/utils/guess.mjs +1 -1
- package/dist/adapters/http/controllers/entities/client/module.mjs +2 -2
- package/dist/adapters/http/controllers/entities/identity-provider/module.d.ts +24 -4
- package/dist/adapters/http/controllers/entities/identity-provider/module.d.ts.map +1 -1
- package/dist/adapters/http/controllers/entities/identity-provider/module.mjs +117 -106
- 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 -4
- package/dist/adapters/http/controllers/entities/identity-provider/types.d.ts.map +1 -1
- package/dist/adapters/http/controllers/entities/realm/module.mjs +2 -2
- package/dist/adapters/http/controllers/entities/session/module.mjs +2 -2
- package/dist/adapters/http/controllers/entities/user/module.mjs +2 -2
- package/dist/adapters/http/controllers/entities/user-authenticator/module.mjs +2 -2
- 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.map +1 -1
- package/dist/adapters/http/controllers/workflows/authorize/module.mjs +14 -5
- package/dist/adapters/http/controllers/workflows/authorize/module.mjs.map +1 -1
- package/dist/adapters/http/controllers/workflows/token/module.d.ts.map +1 -1
- package/dist/adapters/http/controllers/workflows/token/module.mjs +22 -9
- package/dist/adapters/http/controllers/workflows/token/module.mjs.map +1 -1
- package/dist/adapters/http/controllers/workflows/token/utils/extract.mjs +2 -1
- package/dist/adapters/http/controllers/workflows/token/utils/extract.mjs.map +1 -1
- package/dist/adapters/http/middleware/built-in/assets.mjs +1 -1
- package/dist/adapters/http/middleware/built-in/cors.d.ts.map +1 -1
- package/dist/adapters/http/middleware/built-in/cors.mjs.map +1 -1
- 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/request/helpers/param-id.d.ts.map +1 -1
- package/dist/adapters/http/request/helpers/param-id.mjs +2 -1
- package/dist/adapters/http/request/helpers/param-id.mjs.map +1 -1
- package/dist/adapters/http/ui/account-console/module.mjs +1 -1
- package/dist/adapters/http/ui/auth-console/http-client.mjs +1 -1
- package/dist/adapters/http/ui/auth-console/module.mjs +1 -1
- package/dist/adapters/http/ui/console-packages/module.d.ts +1 -1
- package/dist/adapters/http/ui/console-packages/module.mjs +2 -2
- package/dist/adapters/http/ui/console-packages/module.mjs.map +1 -1
- package/dist/adapters/http/ui/shared/html.d.ts.map +1 -1
- package/dist/adapters/http/ui/shared/html.mjs +1 -0
- package/dist/adapters/http/ui/shared/html.mjs.map +1 -1
- package/dist/app/modules/config/normalize.d.ts.map +1 -1
- package/dist/app/modules/config/normalize.mjs +2 -2
- package/dist/app/modules/config/normalize.mjs.map +1 -1
- package/dist/app/modules/config/read/env.mjs +1 -1
- package/dist/app/modules/config/types.d.ts +8 -0
- package/dist/app/modules/config/types.d.ts.map +1 -1
- package/dist/app/modules/database/repositories/event/repository.d.ts +2 -2
- package/dist/app/modules/database/repositories/event/repository.d.ts.map +1 -1
- package/dist/app/modules/database/repositories/event/repository.mjs +23 -6
- package/dist/app/modules/database/repositories/event/repository.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 +2 -2
- package/dist/app/modules/database/repositories/identity-provider/repository.mjs.map +1 -1
- package/dist/app/modules/database/repositories/identity-provider-account/repository.d.ts.map +1 -1
- package/dist/app/modules/database/repositories/identity-provider-account/repository.mjs +9 -1
- package/dist/app/modules/database/repositories/identity-provider-account/repository.mjs.map +1 -1
- package/dist/app/modules/http/modules/controller.d.ts.map +1 -1
- package/dist/app/modules/http/modules/controller.mjs +20 -6
- package/dist/app/modules/http/modules/controller.mjs.map +1 -1
- package/dist/app/modules/identity/module.d.ts.map +1 -1
- package/dist/app/modules/identity/module.mjs +6 -3
- package/dist/app/modules/identity/module.mjs.map +1 -1
- package/dist/app/modules/identity/repositories/user.d.ts +1 -0
- package/dist/app/modules/identity/repositories/user.d.ts.map +1 -1
- package/dist/app/modules/identity/repositories/user.mjs +3 -0
- package/dist/app/modules/identity/repositories/user.mjs.map +1 -1
- package/dist/app/modules/oauth2/constants.d.ts +2 -1
- package/dist/app/modules/oauth2/constants.d.ts.map +1 -1
- package/dist/app/modules/oauth2/constants.mjs +1 -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 +5 -0
- package/dist/app/modules/oauth2/module.mjs.map +1 -1
- package/dist/app/modules/oauth2/repositories/authorize/state/repository.d.ts +1 -2
- package/dist/app/modules/oauth2/repositories/authorize/state/repository.d.ts.map +1 -1
- package/dist/app/modules/oauth2/repositories/authorize/state/repository.mjs +7 -16
- package/dist/app/modules/oauth2/repositories/authorize/state/repository.mjs.map +1 -1
- package/dist/app/modules/oauth2/repositories/constants.d.ts +1 -0
- package/dist/app/modules/oauth2/repositories/constants.d.ts.map +1 -1
- package/dist/app/modules/oauth2/repositories/constants.mjs +1 -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 +1 -0
- package/dist/app/modules/oauth2/repositories/index.d.ts.map +1 -1
- package/dist/app/modules/oauth2/repositories/index.mjs +3 -1
- package/dist/app/modules/runtime/module.mjs +2 -2
- package/dist/cli/commands/migration.mjs +1 -1
- package/dist/core/entities/client-scope/schema.d.ts.map +1 -1
- package/dist/core/entities/client-scope/schema.mjs +16 -1
- package/dist/core/entities/client-scope/schema.mjs.map +1 -1
- package/dist/core/entities/event/constants.d.ts +9 -0
- package/dist/core/entities/event/constants.d.ts.map +1 -1
- package/dist/core/entities/event/constants.mjs +9 -1
- 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 +14 -1
- package/dist/core/entities/event/entity-event-handler.mjs.map +1 -1
- package/dist/core/entities/event/index.mjs +2 -2
- package/dist/core/entities/event/types.d.ts +11 -2
- 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/identity-provider-account/types.d.ts +6 -0
- package/dist/core/entities/identity-provider-account/types.d.ts.map +1 -1
- package/dist/core/entities/identity-provider-account/types.mjs.map +1 -1
- package/dist/core/entities/index.mjs +2 -2
- package/dist/core/identity/entities/user/types.d.ts +1 -0
- package/dist/core/identity/entities/user/types.d.ts.map +1 -1
- package/dist/core/identity/index.mjs +12 -11
- package/dist/core/identity/provider/account/module.d.ts +3 -0
- package/dist/core/identity/provider/account/module.d.ts.map +1 -1
- package/dist/core/identity/provider/account/module.mjs +54 -27
- package/dist/core/identity/provider/account/module.mjs.map +1 -1
- package/dist/core/identity/provider/account/types.d.ts +7 -0
- package/dist/core/identity/provider/account/types.d.ts.map +1 -1
- package/dist/core/identity/provider/authentication/index.mjs +3 -2
- 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 +12 -11
- package/dist/core/index.mjs +16 -12
- package/dist/core/oauth2/authorization/code-request/verifier/module.d.ts.map +1 -1
- package/dist/core/oauth2/authorization/code-request/verifier/module.mjs +7 -1
- package/dist/core/oauth2/authorization/code-request/verifier/module.mjs.map +1 -1
- package/dist/core/oauth2/authorization/helpers.d.ts.map +1 -1
- package/dist/core/oauth2/authorization/helpers.mjs +6 -1
- package/dist/core/oauth2/authorization/helpers.mjs.map +1 -1
- package/dist/core/oauth2/authorization/module.d.ts.map +1 -1
- package/dist/core/oauth2/authorization/module.mjs +5 -3
- package/dist/core/oauth2/authorization/module.mjs.map +1 -1
- package/dist/core/oauth2/authorization/state/module.mjs +1 -2
- package/dist/core/oauth2/authorization/state/module.mjs.map +1 -1
- package/dist/core/oauth2/authorization/state/types.d.ts +13 -2
- package/dist/core/oauth2/authorization/state/types.d.ts.map +1 -1
- package/dist/core/oauth2/end-session/service.d.ts.map +1 -1
- package/dist/core/oauth2/end-session/service.mjs +1 -0
- 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 +4 -0
- package/dist/core/oauth2/federated-login/index.d.ts.map +1 -0
- package/dist/core/oauth2/federated-login/index.mjs +7 -0
- package/dist/core/oauth2/federated-login/module.d.ts +29 -0
- package/dist/core/oauth2/federated-login/module.d.ts.map +1 -0
- package/dist/core/oauth2/federated-login/module.mjs +193 -0
- package/dist/core/oauth2/federated-login/module.mjs.map +1 -0
- package/dist/core/oauth2/federated-login/types.d.ts +196 -0
- package/dist/core/oauth2/federated-login/types.d.ts.map +1 -0
- package/dist/core/oauth2/federated-login/types.mjs +36 -0
- package/dist/core/oauth2/federated-login/types.mjs.map +1 -0
- 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 +1 -0
- package/dist/core/oauth2/index.d.ts.map +1 -1
- package/dist/core/oauth2/index.mjs +5 -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/entities/policy/validator.d.ts.map +1 -1
- package/dist/core/provisioning/entities/policy/validator.mjs +2 -1
- package/dist/core/provisioning/entities/policy/validator.mjs.map +1 -1
- package/dist/core/provisioning/entities/realm/wildcard-validator.d.ts.map +1 -1
- package/dist/core/provisioning/entities/realm/wildcard-validator.mjs +2 -1
- package/dist/core/provisioning/entities/realm/wildcard-validator.mjs.map +1 -1
- package/dist/core/security/policy/evaluator.mjs.map +1 -1
- package/dist/node_modules/@ebec/core/dist/index.mjs +130 -0
- package/dist/node_modules/@ebec/core/dist/index.mjs.map +1 -0
- package/dist/swagger.json +119 -43
- package/dist/utils/error.d.ts.map +1 -1
- package/dist/utils/error.mjs +5 -6
- package/dist/utils/error.mjs.map +1 -1
- package/package.json +29 -29
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entity.d.ts","sourceRoot":"","sources":["../../../../../src/adapters/database/domains/client-scope/entity.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EACR,MAAM,EACN,WAAW,EACX,KAAK,EACL,KAAK,EACR,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGhD,qBAEa,iBAAkB,YAAW,WAAW;IAEjD,EAAE,EAAE,MAAM,CAAC;IAOX,OAAO,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"entity.d.ts","sourceRoot":"","sources":["../../../../../src/adapters/database/domains/client-scope/entity.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EACR,MAAM,EACN,WAAW,EACX,KAAK,EACL,KAAK,EACR,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGhD,qBAEa,iBAAkB,YAAW,WAAW;IAEjD,EAAE,EAAE,MAAM,CAAC;IAOX,OAAO,EAAE,OAAO,CAAC;IAMjB,SAAS,EAAE,MAAM,CAAC;IAIlB,SAAS,EAAE,MAAM,CAAC;IAKlB,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;IAIvB,MAAM,EAAE,MAAM,CAAC;IAIf,aAAa,EAAE,KAAK,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAOlC,WAAW,EAAE,WAAW,GAAG,IAAI,CAAC;IAMhC,OAAO,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;IAIrB,KAAK,EAAE,KAAK,CAAC;IAIb,YAAY,EAAE,KAAK,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAOjC,UAAU,EAAE,WAAW,GAAG,IAAI,CAAC;CAClC"}
|
|
@@ -43,14 +43,22 @@ _ts_decorate([
|
|
|
43
43
|
}),
|
|
44
44
|
_ts_metadata("design:type", Boolean)
|
|
45
45
|
], ClientScopeEntity.prototype, "default", void 0);
|
|
46
|
-
_ts_decorate([
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
46
|
+
_ts_decorate([
|
|
47
|
+
Index(),
|
|
48
|
+
CreateDateColumn({
|
|
49
|
+
name: "created_at",
|
|
50
|
+
transformer: dateToISOStringTransformer
|
|
51
|
+
}),
|
|
52
|
+
_ts_metadata("design:type", String)
|
|
53
|
+
], ClientScopeEntity.prototype, "createdAt", void 0);
|
|
54
|
+
_ts_decorate([
|
|
55
|
+
Index(),
|
|
56
|
+
UpdateDateColumn({
|
|
57
|
+
name: "updated_at",
|
|
58
|
+
transformer: dateToISOStringTransformer
|
|
59
|
+
}),
|
|
60
|
+
_ts_metadata("design:type", String)
|
|
61
|
+
], ClientScopeEntity.prototype, "updatedAt", void 0);
|
|
54
62
|
_ts_decorate([Column({ name: "client_id" }), _ts_metadata("design:type", Object)], ClientScopeEntity.prototype, "clientId", void 0);
|
|
55
63
|
_ts_decorate([
|
|
56
64
|
ManyToOne(() => ClientEntity, { onDelete: "CASCADE" }),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entity.mjs","names":["Column","CreateDateColumn","Entity","Index","JoinColumn","ManyToOne","PrimaryGeneratedColumn","Unique","UpdateDateColumn","dateToISOStringTransformer","ClientEntity","RealmEntity","ScopeEntity","ClientScopeEntity","id","default","createdAt","updatedAt","clientId","client","clientRealmId","clientRealm","scopeId","scope","scopeRealmId","scopeRealm","type","name","transformer","onDelete","nullable"],"sources":["../../../../../src/adapters/database/domains/client-scope/entity.ts"],"sourcesContent":["/*\n * Copyright (c) 2021-2021.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport {\n Column,\n CreateDateColumn,\n Entity,\n Index,\n JoinColumn,\n ManyToOne,\n PrimaryGeneratedColumn,\n Unique,\n UpdateDateColumn,\n} from 'typeorm';\nimport { dateToISOStringTransformer } from '../../helpers/index.ts';\nimport type {\n Client,\n ClientScope,\n Realm,\n Scope,\n} from '@authup/core-kit';\nimport { ClientEntity } from '../client/index.ts';\nimport { RealmEntity } from '../realm/index.ts';\nimport { ScopeEntity } from '../scope/index.ts';\n\n@Entity({ name: 'auth_client_scopes' })\n@Unique(['clientId', 'scopeId'])\nexport class ClientScopeEntity implements ClientScope {\n @PrimaryGeneratedColumn('uuid')\n id: string;\n\n @Index()\n @Column({\n type: 'boolean',\n default: false, \n })\n default: boolean;\n\n // ------------------------------------------------------------------\n\n @CreateDateColumn({ name: 'created_at', transformer: dateToISOStringTransformer })\n createdAt: string;\n\n @UpdateDateColumn({ name: 'updated_at', transformer: dateToISOStringTransformer })\n updatedAt: string;\n\n // ------------------------------------------------------------------\n\n @Column({ name: 'client_id' })\n clientId: Client['id'];\n\n @ManyToOne(() => ClientEntity, { onDelete: 'CASCADE' })\n @JoinColumn({ name: 'client_id' })\n client: Client;\n\n @Index()\n @Column({ name: 'client_realm_id', nullable: true })\n clientRealmId: Realm['id'] | null;\n\n @ManyToOne(() => RealmEntity, {\n onDelete: 'CASCADE',\n nullable: true, \n })\n @JoinColumn({ name: 'client_realm_id' })\n clientRealm: RealmEntity | null;\n\n // ------------------------------------------------------------------\n\n @Index()\n @Column({ name: 'scope_id' })\n scopeId: Scope['id'];\n\n @ManyToOne(() => ScopeEntity, { onDelete: 'CASCADE' })\n @JoinColumn({ name: 'scope_id' })\n scope: Scope;\n\n @Index()\n @Column({ name: 'scope_realm_id', nullable: true })\n scopeRealmId: Realm['id'] | null;\n\n @ManyToOne(() => RealmEntity, {\n onDelete: 'CASCADE',\n nullable: true, \n })\n @JoinColumn({ name: 'scope_realm_id' })\n scopeRealm: RealmEntity | null;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AA+BA,IAAaa,oBAAb,MAAaA;CAETC;CAOAC;
|
|
1
|
+
{"version":3,"file":"entity.mjs","names":["Column","CreateDateColumn","Entity","Index","JoinColumn","ManyToOne","PrimaryGeneratedColumn","Unique","UpdateDateColumn","dateToISOStringTransformer","ClientEntity","RealmEntity","ScopeEntity","ClientScopeEntity","id","default","createdAt","updatedAt","clientId","client","clientRealmId","clientRealm","scopeId","scope","scopeRealmId","scopeRealm","type","name","transformer","onDelete","nullable"],"sources":["../../../../../src/adapters/database/domains/client-scope/entity.ts"],"sourcesContent":["/*\n * Copyright (c) 2021-2021.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport {\n Column,\n CreateDateColumn,\n Entity,\n Index,\n JoinColumn,\n ManyToOne,\n PrimaryGeneratedColumn,\n Unique,\n UpdateDateColumn,\n} from 'typeorm';\nimport { dateToISOStringTransformer } from '../../helpers/index.ts';\nimport type {\n Client,\n ClientScope,\n Realm,\n Scope,\n} from '@authup/core-kit';\nimport { ClientEntity } from '../client/index.ts';\nimport { RealmEntity } from '../realm/index.ts';\nimport { ScopeEntity } from '../scope/index.ts';\n\n@Entity({ name: 'auth_client_scopes' })\n@Unique(['clientId', 'scopeId'])\nexport class ClientScopeEntity implements ClientScope {\n @PrimaryGeneratedColumn('uuid')\n id: string;\n\n @Index()\n @Column({\n type: 'boolean',\n default: false, \n })\n default: boolean;\n\n // ------------------------------------------------------------------\n\n @Index()\n @CreateDateColumn({ name: 'created_at', transformer: dateToISOStringTransformer })\n createdAt: string;\n\n @Index()\n @UpdateDateColumn({ name: 'updated_at', transformer: dateToISOStringTransformer })\n updatedAt: string;\n\n // ------------------------------------------------------------------\n\n @Column({ name: 'client_id' })\n clientId: Client['id'];\n\n @ManyToOne(() => ClientEntity, { onDelete: 'CASCADE' })\n @JoinColumn({ name: 'client_id' })\n client: Client;\n\n @Index()\n @Column({ name: 'client_realm_id', nullable: true })\n clientRealmId: Realm['id'] | null;\n\n @ManyToOne(() => RealmEntity, {\n onDelete: 'CASCADE',\n nullable: true, \n })\n @JoinColumn({ name: 'client_realm_id' })\n clientRealm: RealmEntity | null;\n\n // ------------------------------------------------------------------\n\n @Index()\n @Column({ name: 'scope_id' })\n scopeId: Scope['id'];\n\n @ManyToOne(() => ScopeEntity, { onDelete: 'CASCADE' })\n @JoinColumn({ name: 'scope_id' })\n scope: Scope;\n\n @Index()\n @Column({ name: 'scope_realm_id', nullable: true })\n scopeRealmId: Realm['id'] | null;\n\n @ManyToOne(() => RealmEntity, {\n onDelete: 'CASCADE',\n nullable: true, \n })\n @JoinColumn({ name: 'scope_realm_id' })\n scopeRealm: RealmEntity | null;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AA+BA,IAAaa,oBAAb,MAAaA;CAETC;CAOAC;CAMAC;CAIAC;CAKAC;CAIAC;CAIAC;CAOAC;CAMAC;CAIAC;CAIAC;CAOAC;AACJ;;;;;EAvDQC,MAAM;EACNX,SAAS;;;;;;;EAOOY,MAAM;EAAcC,aAAanB;;;;;;;EAIjCkB,MAAM;EAAcC,aAAanB;;;;AAK3CkB,aAAAA,CAAAA,OAAAA,EAAAA,MAAM,YAAA,CAAA,GAAA,aAAA,eAAA,MAAA,CAAA,GAAA,kBAAA,WAAA,YAAA,KAAA,CAAA;;CAGCjB,gBAAAA,cAAAA,EAAgBmB,UAAU,UAAA,CAAA;CAC7BF,WAAAA,EAAAA,MAAM,YAAA,CAAA;;;;;;EAIVA,MAAM;EAAmBG,UAAU;;;;;CAG5BnB,gBAAAA,aAAAA;EACbkB,UAAU;EACVC,UAAU;;CAEAH,WAAAA,EAAAA,MAAM,kBAAA,CAAA;;;;;CAMVA,OAAAA,EAAAA,MAAM,WAAA,CAAA;;;;CAGCf,gBAAAA,aAAAA,EAAeiB,UAAU,UAAA,CAAA;CAC5BF,WAAAA,EAAAA,MAAM,WAAA,CAAA;;;;;;EAIVA,MAAM;EAAkBG,UAAU;;;;;CAG3BnB,gBAAAA,aAAAA;EACbkB,UAAU;EACVC,UAAU;;CAEAH,WAAAA,EAAAA,MAAM,iBAAA,CAAA;;;AA7DdA,oBAAAA,aAAAA,CAAAA,OAAAA,EAAAA,MAAM,qBAAA,CAAA,GAAA,OAAA,CACP,YAAY,SAAA,CAAA,CAAA,GAAA,iBAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entity.d.ts","sourceRoot":"","sources":["../../../../../src/adapters/database/domains/identity-provider-account/entity.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAER,gBAAgB,EAChB,uBAAuB,EACvB,KAAK,EACL,IAAI,EACP,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AAEvE,
|
|
1
|
+
{"version":3,"file":"entity.d.ts","sourceRoot":"","sources":["../../../../../src/adapters/database/domains/identity-provider-account/entity.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAER,gBAAgB,EAChB,uBAAuB,EACvB,KAAK,EACL,IAAI,EACP,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AAEvE,qBAMa,6BAA8B,YAAW,uBAAuB;IAEzE,EAAE,EAAE,MAAM,CAAC;IASX,WAAW,EAAE,MAAM,CAAC;IASpB,YAAY,EAAE,MAAM,CAAC;IAOrB,cAAc,EAAE,MAAM,CAAC;IASvB,gBAAgB,EAAE,MAAM,CAAC;IASzB,iBAAiB,EAAE,MAAM,CAAC;IAU1B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAUzB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAIzB,SAAS,EAAE,MAAM,CAAC;IAIlB,SAAS,EAAE,MAAM,CAAC;IAMlB,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;IAInB,IAAI,EAAE,UAAU,CAAC;IAIjB,WAAW,EAAE,KAAK,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAOhC,SAAS,EAAE,WAAW,GAAG,IAAI,CAAC;IAK9B,UAAU,EAAE,gBAAgB,CAAC,IAAI,CAAC,CAAC;IAInC,QAAQ,EAAE,sBAAsB,CAAC;IAIjC,eAAe,EAAE,KAAK,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAOpC,aAAa,EAAE,WAAW,GAAG,IAAI,CAAC;CACrC"}
|
|
@@ -157,7 +157,7 @@ _ts_decorate([
|
|
|
157
157
|
IdentityProviderAccountEntity = _ts_decorate([
|
|
158
158
|
Entity({ name: "auth_identity_provider_accounts" }),
|
|
159
159
|
Index(["providerId", "userId"], { unique: true }),
|
|
160
|
-
Index(["providerUserId", "providerId"])
|
|
160
|
+
Index(["providerUserId", "providerId"], { unique: true })
|
|
161
161
|
], IdentityProviderAccountEntity);
|
|
162
162
|
//#endregion
|
|
163
163
|
export { IdentityProviderAccountEntity };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entity.mjs","names":["Column","CreateDateColumn","Entity","Index","JoinColumn","ManyToOne","PrimaryGeneratedColumn","UpdateDateColumn","dateToISOStringTransformer","RealmEntity","UserEntity","IdentityProviderEntity","IdentityProviderAccountEntity","id","accessToken","refreshToken","providerUserId","providerUserName","providerUserEmail","expiresIn","expiresAt","createdAt","updatedAt","userId","user","userRealmId","userRealm","providerId","provider","providerRealmId","providerRealm","name","type","nullable","default","select","length","unsigned","transformer","onDelete","unique"],"sources":["../../../../../src/adapters/database/domains/identity-provider-account/entity.ts"],"sourcesContent":["/*\n * Copyright (c) 2022.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport {\n Column,\n CreateDateColumn,\n Entity,\n Index,\n JoinColumn,\n ManyToOne,\n PrimaryGeneratedColumn,\n UpdateDateColumn,\n} from 'typeorm';\nimport { dateToISOStringTransformer } from '../../helpers/index.ts';\nimport type {\n \n IdentityProvider, \n IdentityProviderAccount, \n Realm, \n User, \n} from '@authup/core-kit';\nimport { RealmEntity } from '../realm/index.ts';\nimport { UserEntity } from '../user/index.ts';\nimport { IdentityProviderEntity } from '../identity-provider/index.ts';\n\n@Entity({ name: 'auth_identity_provider_accounts' })\n@Index(['providerId', 'userId'], { unique: true })\n@Index(['providerUserId', 'providerId'])\nexport class IdentityProviderAccountEntity implements IdentityProviderAccount {\n @PrimaryGeneratedColumn('uuid')\n id: string;\n\n @Column({\n name: 'access_token',\n type: 'text',\n nullable: true,\n default: null,\n select: false,\n })\n accessToken: string;\n\n @Column({\n name: 'refresh_token',\n type: 'text',\n nullable: true,\n default: null,\n select: false,\n })\n refreshToken: string;\n\n @Column({\n name: 'provider_user_id', \n type: 'varchar', \n length: 256, \n })\n providerUserId: string;\n\n @Column({\n name: 'provider_user_name', \n type: 'varchar', \n length: 256, \n nullable: true, \n default: null, \n })\n providerUserName: string;\n\n @Column({\n name: 'provider_user_email', \n type: 'varchar', \n length: 512, \n nullable: true, \n default: null, \n })\n providerUserEmail: string;\n\n @Column({\n name: 'expires_in',\n type: 'int',\n unsigned: true,\n nullable: true,\n default: null,\n select: false,\n })\n expiresIn: number | null;\n\n @Column({\n name: 'expires_at',\n type: 'varchar',\n length: 28,\n nullable: true,\n default: null,\n select: false,\n })\n expiresAt: string | null;\n\n @Index()\n @CreateDateColumn({ name: 'created_at', transformer: dateToISOStringTransformer })\n createdAt: string;\n\n @Index()\n @UpdateDateColumn({ name: 'updated_at', transformer: dateToISOStringTransformer })\n updatedAt: string;\n\n // -----------------------------------------------\n\n @Index()\n @Column({ name: 'user_id' })\n userId: User['id'];\n\n @ManyToOne(() => UserEntity, { onDelete: 'CASCADE' })\n @JoinColumn({ name: 'user_id' })\n user: UserEntity;\n\n @Index()\n @Column({ name: 'user_realm_id', nullable: true })\n userRealmId: Realm['id'] | null;\n\n @ManyToOne(() => RealmEntity, {\n onDelete: 'CASCADE',\n nullable: true, \n })\n @JoinColumn({ name: 'user_realm_id' })\n userRealm: RealmEntity | null;\n\n // -----------------------------------------------\n\n @Column({ name: 'provider_id' })\n providerId: IdentityProvider['id'];\n\n @ManyToOne(() => IdentityProviderEntity, { onDelete: 'CASCADE' })\n @JoinColumn({ name: 'provider_id' })\n provider: IdentityProviderEntity;\n\n @Index()\n @Column({ name: 'provider_realm_id', nullable: true })\n providerRealmId: Realm['id'] | null;\n\n @ManyToOne(() => RealmEntity, {\n onDelete: 'CASCADE',\n nullable: true, \n })\n @JoinColumn({ name: 'provider_realm_id' })\n providerRealm: RealmEntity | null;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"entity.mjs","names":["Column","CreateDateColumn","Entity","Index","JoinColumn","ManyToOne","PrimaryGeneratedColumn","UpdateDateColumn","dateToISOStringTransformer","RealmEntity","UserEntity","IdentityProviderEntity","IdentityProviderAccountEntity","id","accessToken","refreshToken","providerUserId","providerUserName","providerUserEmail","expiresIn","expiresAt","createdAt","updatedAt","userId","user","userRealmId","userRealm","providerId","provider","providerRealmId","providerRealm","name","type","nullable","default","select","length","unsigned","transformer","onDelete","unique"],"sources":["../../../../../src/adapters/database/domains/identity-provider-account/entity.ts"],"sourcesContent":["/*\n * Copyright (c) 2022.\n * Author Peter Placzek (tada5hi)\n * For the full copyright and license information,\n * view the LICENSE file that was distributed with this source code.\n */\n\nimport {\n Column,\n CreateDateColumn,\n Entity,\n Index,\n JoinColumn,\n ManyToOne,\n PrimaryGeneratedColumn,\n UpdateDateColumn,\n} from 'typeorm';\nimport { dateToISOStringTransformer } from '../../helpers/index.ts';\nimport type {\n \n IdentityProvider, \n IdentityProviderAccount, \n Realm, \n User, \n} from '@authup/core-kit';\nimport { RealmEntity } from '../realm/index.ts';\nimport { UserEntity } from '../user/index.ts';\nimport { IdentityProviderEntity } from '../identity-provider/index.ts';\n\n@Entity({ name: 'auth_identity_provider_accounts' })\n@Index(['providerId', 'userId'], { unique: true })\n// one external identity belongs to one local user. The column order is\n// load-bearing: `providerUserId` leads the sequence the rapiq schema\n// declares, and reversing it would fail the boot-time index assertion.\n@Index(['providerUserId', 'providerId'], { unique: true })\nexport class IdentityProviderAccountEntity implements IdentityProviderAccount {\n @PrimaryGeneratedColumn('uuid')\n id: string;\n\n @Column({\n name: 'access_token',\n type: 'text',\n nullable: true,\n default: null,\n select: false,\n })\n accessToken: string;\n\n @Column({\n name: 'refresh_token',\n type: 'text',\n nullable: true,\n default: null,\n select: false,\n })\n refreshToken: string;\n\n @Column({\n name: 'provider_user_id', \n type: 'varchar', \n length: 256, \n })\n providerUserId: string;\n\n @Column({\n name: 'provider_user_name', \n type: 'varchar', \n length: 256, \n nullable: true, \n default: null, \n })\n providerUserName: string;\n\n @Column({\n name: 'provider_user_email', \n type: 'varchar', \n length: 512, \n nullable: true, \n default: null, \n })\n providerUserEmail: string;\n\n @Column({\n name: 'expires_in',\n type: 'int',\n unsigned: true,\n nullable: true,\n default: null,\n select: false,\n })\n expiresIn: number | null;\n\n @Column({\n name: 'expires_at',\n type: 'varchar',\n length: 28,\n nullable: true,\n default: null,\n select: false,\n })\n expiresAt: string | null;\n\n @Index()\n @CreateDateColumn({ name: 'created_at', transformer: dateToISOStringTransformer })\n createdAt: string;\n\n @Index()\n @UpdateDateColumn({ name: 'updated_at', transformer: dateToISOStringTransformer })\n updatedAt: string;\n\n // -----------------------------------------------\n\n @Index()\n @Column({ name: 'user_id' })\n userId: User['id'];\n\n @ManyToOne(() => UserEntity, { onDelete: 'CASCADE' })\n @JoinColumn({ name: 'user_id' })\n user: UserEntity;\n\n @Index()\n @Column({ name: 'user_realm_id', nullable: true })\n userRealmId: Realm['id'] | null;\n\n @ManyToOne(() => RealmEntity, {\n onDelete: 'CASCADE',\n nullable: true, \n })\n @JoinColumn({ name: 'user_realm_id' })\n userRealm: RealmEntity | null;\n\n // -----------------------------------------------\n\n @Column({ name: 'provider_id' })\n providerId: IdentityProvider['id'];\n\n @ManyToOne(() => IdentityProviderEntity, { onDelete: 'CASCADE' })\n @JoinColumn({ name: 'provider_id' })\n provider: IdentityProviderEntity;\n\n @Index()\n @Column({ name: 'provider_realm_id', nullable: true })\n providerRealmId: Realm['id'] | null;\n\n @ManyToOne(() => RealmEntity, {\n onDelete: 'CASCADE',\n nullable: true, \n })\n @JoinColumn({ name: 'provider_realm_id' })\n providerRealm: RealmEntity | null;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAmCA,IAAaY,gCAAb,MAAaA;CAETC;CASAC;CASAC;CAOAC;CASAC;CASAC;CAUAC;CAUAC;CAIAC;CAIAC;CAMAC;CAIAC;CAIAC;CAOAC;CAKAC;CAIAC;CAIAC;CAOAC;AACJ;;;CA9GQC,MAAM;CACNC,MAAM;CACNC,UAAU;CACVC,SAAS;CACTC,QAAQ;;;CAKRJ,MAAM;CACNC,MAAM;CACNC,UAAU;CACVC,SAAS;CACTC,QAAQ;;;CAKRJ,MAAM;CACNC,MAAM;CACNI,QAAQ;;;CAKRL,MAAM;CACNC,MAAM;CACNI,QAAQ;CACRH,UAAU;CACVC,SAAS;;;CAKTH,MAAM;CACNC,MAAM;CACNI,QAAQ;CACRH,UAAU;CACVC,SAAS;;;CAKTH,MAAM;CACNC,MAAM;CACNK,UAAU;CACVJ,UAAU;CACVC,SAAS;CACTC,QAAQ;;;CAKRJ,MAAM;CACNC,MAAM;CACNI,QAAQ;CACRH,UAAU;CACVC,SAAS;CACTC,QAAQ;;;;;EAKQJ,MAAM;EAAcO,aAAa9B;;;;;;;EAIjCuB,MAAM;EAAcO,aAAa9B;;;;;;CAM3CuB,OAAAA,EAAAA,MAAM,UAAA,CAAA;;;;CAGCrB,gBAAAA,YAAAA,EAAc6B,UAAU,UAAA,CAAA;CAC3BR,WAAAA,EAAAA,MAAM,UAAA,CAAA;;;;;;EAIVA,MAAM;EAAiBE,UAAU;;;;;CAG1BxB,gBAAAA,aAAAA;EACb8B,UAAU;EACVN,UAAU;;CAEAF,WAAAA,EAAAA,MAAM,gBAAA,CAAA;;;AAKVA,aAAAA,CAAAA,OAAAA,EAAAA,MAAM,cAAA,CAAA,GAAA,aAAA,eAAA,MAAA,CAAA,GAAA,8BAAA,WAAA,cAAA,KAAA,CAAA;;CAGCpB,gBAAAA,wBAAAA,EAA0B4B,UAAU,UAAA,CAAA;CACvCR,WAAAA,EAAAA,MAAM,cAAA,CAAA;;;;;;EAIVA,MAAM;EAAqBE,UAAU;;;;;CAG9BxB,gBAAAA,aAAAA;EACb8B,UAAU;EACVN,UAAU;;CAEAF,WAAAA,EAAAA,MAAM,oBAAA,CAAA;;;;CAvHdA,OAAAA,EAAAA,MAAM,kCAAA,CAAA;CACR,MAAA,CAAA,cAAc,QAAA,GAAA,EAAaS,QAAQ,KAAA,CAAA;CAInC,MAAA,CAAA,kBAAkB,YAAA,GAAA,EAAiBA,QAAQ,KAAA,CAAA"}
|
|
@@ -1,6 +1,13 @@
|
|
|
1
|
-
import type { IdentityProviderAttribute } from '@authup/core-kit';
|
|
1
|
+
import type { EntityDefaultEventName, IdentityProviderAttribute } from '@authup/core-kit';
|
|
2
2
|
import { EntitySubscriber } from '../../subscriber/index.ts';
|
|
3
3
|
export declare class IdentityProviderAttributeSubscriber extends EntitySubscriber<IdentityProviderAttribute> {
|
|
4
4
|
constructor();
|
|
5
|
+
/**
|
|
6
|
+
* The row's `value` holds the provider's OAuth2 clientSecret or LDAP bind
|
|
7
|
+
* password, so it must never reach the realtime bus. Stripped on both
|
|
8
|
+
* sides: the previous payload is what an update would otherwise carry the
|
|
9
|
+
* OLD secret in.
|
|
10
|
+
*/
|
|
11
|
+
protected publish(event: `${EntityDefaultEventName}`, data: IdentityProviderAttribute, dataPrevious?: IdentityProviderAttribute): Promise<void>;
|
|
5
12
|
}
|
|
6
13
|
//# sourceMappingURL=subscriber.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"subscriber.d.ts","sourceRoot":"","sources":["../../../../../src/adapters/database/domains/identity-provider-attribute/subscriber.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"subscriber.d.ts","sourceRoot":"","sources":["../../../../../src/adapters/database/domains/identity-provider-attribute/subscriber.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,sBAAsB,EAAE,yBAAyB,EAAE,MAAM,kBAAkB,CAAC;AAI1F,OAAO,EAAE,gBAAgB,EAA2B,MAAM,2BAA2B,CAAC;AAItF,qBACa,mCAAoC,SAAQ,gBAAgB,CAAC,yBAAyB,CAAC;;IAiBhG;;;;;OAKG;cACsB,OAAO,CAC5B,KAAK,EAAE,GAAG,sBAAsB,EAAE,EAClC,IAAI,EAAE,yBAAyB,EAC/B,YAAY,CAAC,EAAE,yBAAyB,GACzC,OAAO,CAAC,IAAI,CAAC;CAOnB"}
|
|
@@ -30,6 +30,20 @@ var IdentityProviderAttributeSubscriber = class extends EntitySubscriber {
|
|
|
30
30
|
})] }
|
|
31
31
|
});
|
|
32
32
|
}
|
|
33
|
+
/**
|
|
34
|
+
* The row's `value` holds the provider's OAuth2 clientSecret or LDAP bind
|
|
35
|
+
* password, so it must never reach the realtime bus. Stripped on both
|
|
36
|
+
* sides: the previous payload is what an update would otherwise carry the
|
|
37
|
+
* OLD secret in.
|
|
38
|
+
*/ async publish(event, data, dataPrevious) {
|
|
39
|
+
await super.publish(event, {
|
|
40
|
+
...data,
|
|
41
|
+
value: null
|
|
42
|
+
}, dataPrevious ? {
|
|
43
|
+
...dataPrevious,
|
|
44
|
+
value: null
|
|
45
|
+
} : void 0);
|
|
46
|
+
}
|
|
33
47
|
};
|
|
34
48
|
IdentityProviderAttributeSubscriber = _ts_decorate([
|
|
35
49
|
EventSubscriber(),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"subscriber.mjs","names":["EntityType","buildRedisKeyPath","EventSubscriber","EntitySubscriber","buildEntityDestinations","IdentityProviderAttributeEntity","CachePrefix","IdentityProviderAttributeSubscriber","type","IDENTITY_PROVIDER_ATTRIBUTE","target","destinations","cache","keys","data","prefix","key","id"],"sources":["../../../../../src/adapters/database/domains/identity-provider-attribute/subscriber.ts"],"sourcesContent":["/*\n * Copyright (c) 2022-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 type { IdentityProviderAttribute } from '@authup/core-kit';\nimport { EntityType } from '@authup/core-kit';\nimport { buildRedisKeyPath } from '@authup/server-kit';\nimport { EventSubscriber } from 'typeorm';\nimport { EntitySubscriber, buildEntityDestinations } from '../../subscriber/index.ts';\nimport { IdentityProviderAttributeEntity } from './entity.ts';\nimport { CachePrefix } from '../constants.ts';\n\n@EventSubscriber()\nexport class IdentityProviderAttributeSubscriber extends EntitySubscriber<IdentityProviderAttribute> {\n constructor() {\n super({\n type: EntityType.IDENTITY_PROVIDER_ATTRIBUTE,\n target: IdentityProviderAttributeEntity,\n destinations: buildEntityDestinations(EntityType.IDENTITY_PROVIDER_ATTRIBUTE),\n cache: {\n keys: (data) => [\n buildRedisKeyPath({\n prefix: CachePrefix.IDENTITY_PROVIDER_ATTRIBUTE,\n key: data.id,\n }),\n ],\n },\n });\n }\n}\n"],"mappings":";;;;;;;;;;;AAKC,SAAA,aAAA,YAAA,QAAA,KAAA,MAAA;;;;;;;;;AAWD,IAAaO,sCAAb,cAAyDJ,iBAAAA;CACrD,cAAc;EACV,MAAM;GACFK,MAAMR,WAAWS;GACjBC,QAAQL;GACRM,cAAcP,wBAAwBJ,WAAWS,2BAA2B;GAC5EG,OAAO,EACHC,OAAOC,SAAS,CACZb,kBAAkB;IACdc,QAAQT,YAAYG;IACpBO,KAAKF,KAAKG;GACd,CAAA,CACH,EACL;EACJ,CAAA;CACJ;AACJ"}
|
|
1
|
+
{"version":3,"file":"subscriber.mjs","names":["EntityType","buildRedisKeyPath","EventSubscriber","EntitySubscriber","buildEntityDestinations","IdentityProviderAttributeEntity","CachePrefix","IdentityProviderAttributeSubscriber","type","IDENTITY_PROVIDER_ATTRIBUTE","target","destinations","cache","keys","data","prefix","key","id","publish","event","dataPrevious","value","undefined"],"sources":["../../../../../src/adapters/database/domains/identity-provider-attribute/subscriber.ts"],"sourcesContent":["/*\n * Copyright (c) 2022-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 type { EntityDefaultEventName, IdentityProviderAttribute } from '@authup/core-kit';\nimport { EntityType } from '@authup/core-kit';\nimport { buildRedisKeyPath } from '@authup/server-kit';\nimport { EventSubscriber } from 'typeorm';\nimport { EntitySubscriber, buildEntityDestinations } from '../../subscriber/index.ts';\nimport { IdentityProviderAttributeEntity } from './entity.ts';\nimport { CachePrefix } from '../constants.ts';\n\n@EventSubscriber()\nexport class IdentityProviderAttributeSubscriber extends EntitySubscriber<IdentityProviderAttribute> {\n constructor() {\n super({\n type: EntityType.IDENTITY_PROVIDER_ATTRIBUTE,\n target: IdentityProviderAttributeEntity,\n destinations: buildEntityDestinations(EntityType.IDENTITY_PROVIDER_ATTRIBUTE),\n cache: {\n keys: (data) => [\n buildRedisKeyPath({\n prefix: CachePrefix.IDENTITY_PROVIDER_ATTRIBUTE,\n key: data.id,\n }),\n ],\n },\n });\n }\n\n /**\n * The row's `value` holds the provider's OAuth2 clientSecret or LDAP bind\n * password, so it must never reach the realtime bus. Stripped on both\n * sides: the previous payload is what an update would otherwise carry the\n * OLD secret in.\n */\n protected override async publish(\n event: `${EntityDefaultEventName}`,\n data: IdentityProviderAttribute,\n dataPrevious?: IdentityProviderAttribute,\n ): Promise<void> {\n await super.publish(\n event,\n { ...data, value: null },\n dataPrevious ? { ...dataPrevious, value: null } : undefined,\n );\n }\n}\n"],"mappings":";;;;;;;;;;;AAKC,SAAA,aAAA,YAAA,QAAA,KAAA,MAAA;;;;;;;;;AAWD,IAAaO,sCAAb,cAAyDJ,iBAAAA;CACrD,cAAc;EACV,MAAM;GACFK,MAAMR,WAAWS;GACjBC,QAAQL;GACRM,cAAcP,wBAAwBJ,WAAWS,2BAA2B;GAC5EG,OAAO,EACHC,OAAOC,SAAS,CACZb,kBAAkB;IACdc,QAAQT,YAAYG;IACpBO,KAAKF,KAAKG;GACd,CAAA,CACH,EACL;EACJ,CAAA;CACJ;;;;;;IAQA,MAAyBC,QACrBC,OACAL,MACAM,cACa;EACb,MAAM,MAAMF,QACRC,OACA;GAAE,GAAGL;GAAMO,OAAO;EAAK,GACvBD,eAAe;GAAE,GAAGA;GAAcC,OAAO;EAAK,IAAIC,KAAAA,CAAAA;CAE1D;AACJ"}
|
package/dist/adapters/database/migrations/mysql/1786631686318-SortIndexesAndAccountUniqueness.d.ts
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { MigrationInterface, QueryRunner } from 'typeorm';
|
|
2
|
+
/**
|
|
3
|
+
* Client-scope sort indexes (issue #3441) and identity-provider account
|
|
4
|
+
* uniqueness (issue #3442).
|
|
5
|
+
*
|
|
6
|
+
* - Indexes `auth_client_scopes.created_at` and `updated_at`.
|
|
7
|
+
* `clientScopeSchema` was the only registered schema with no `sorts`
|
|
8
|
+
* allow-list, so rapiq fell back to a syntactic name check and handed an
|
|
9
|
+
* arbitrary `?sort=` key to `ORDER BY`. Declaring the allow-list requires
|
|
10
|
+
* every listed key to lead a real entity index; the two timestamp columns
|
|
11
|
+
* were the only ones missing theirs.
|
|
12
|
+
* - Makes `(provider_user_id, provider_id)` unique on
|
|
13
|
+
* `auth_identity_provider_accounts`. "One external identity belongs to one
|
|
14
|
+
* local user" was enforced only by a read-then-write in
|
|
15
|
+
* `IdentityProviderAccountManager`: no transaction, no row lock, and
|
|
16
|
+
* nothing behind it in the schema, so two concurrent completions for the
|
|
17
|
+
* same upstream subject could both observe "not linked" and both insert.
|
|
18
|
+
* After that the subject resolves to whichever row the database happens to
|
|
19
|
+
* order first. The column order matches the pre-existing non-unique index,
|
|
20
|
+
* so this is an in-place uniqueness flip under the same derived name
|
|
21
|
+
* rather than a rename.
|
|
22
|
+
*
|
|
23
|
+
* MySQL commits DDL implicitly, so `migrationsTransactionMode: 'all'` cannot
|
|
24
|
+
* roll a partial run back. A DROP followed by a CREATE would leave the table
|
|
25
|
+
* with no index of that name if the process died between them, and every
|
|
26
|
+
* later attempt would then fail at the DROP. One ALTER carrying both is
|
|
27
|
+
* atomic, so the uniqueness flip either applies or does not.
|
|
28
|
+
*
|
|
29
|
+
* Pre-existing duplicates abort the boot with an actionable message. They
|
|
30
|
+
* would abort it anyway, since `CREATE UNIQUE INDEX` fails on them; the
|
|
31
|
+
* check only decides whether the operator reads a readable sentence or a
|
|
32
|
+
* hash-named driver error.
|
|
33
|
+
*
|
|
34
|
+
* It runs BEFORE any DDL for the same implicit-commit reason: an abort
|
|
35
|
+
* after the two CREATE INDEX statements leaves them committed while the
|
|
36
|
+
* migration stays unapplied, so the operator's retry — after cleaning the
|
|
37
|
+
* duplicates — would die on `Duplicate key name` and never reach the flip.
|
|
38
|
+
* Nothing here writes before the check, so a refusal leaves the schema
|
|
39
|
+
* exactly as it was.
|
|
40
|
+
*
|
|
41
|
+
* Generated with `migration generate`; derived IDX_<hash> names, generated
|
|
42
|
+
* DDL untouched (the duplicate pre-check and the single-ALTER flip are
|
|
43
|
+
* hand-authored).
|
|
44
|
+
*/
|
|
45
|
+
export declare class SortIndexesAndAccountUniqueness1786631686318 implements MigrationInterface {
|
|
46
|
+
name: string;
|
|
47
|
+
up(queryRunner: QueryRunner): Promise<void>;
|
|
48
|
+
down(queryRunner: QueryRunner): Promise<void>;
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=1786631686318-SortIndexesAndAccountUniqueness.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"1786631686318-SortIndexesAndAccountUniqueness.d.ts","sourceRoot":"","sources":["../../../../../src/adapters/database/migrations/mysql/1786631686318-SortIndexesAndAccountUniqueness.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAE/D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AACH,qBAAa,4CAA6C,YAAW,kBAAkB;IACnF,IAAI,SAAkD;IAEzC,EAAE,CAAC,WAAW,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IA6B3C,IAAI,CAAC,WAAW,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;CAa7D"}
|
package/dist/adapters/database/migrations/mysql/1786631686318-SortIndexesAndAccountUniqueness.mjs
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import "node:path";
|
|
2
|
+
import "node:url";
|
|
3
|
+
import.meta.url;
|
|
4
|
+
//#region src/adapters/database/migrations/mysql/1786631686318-SortIndexesAndAccountUniqueness.ts
|
|
5
|
+
/**
|
|
6
|
+
* Client-scope sort indexes (issue #3441) and identity-provider account
|
|
7
|
+
* uniqueness (issue #3442).
|
|
8
|
+
*
|
|
9
|
+
* - Indexes `auth_client_scopes.created_at` and `updated_at`.
|
|
10
|
+
* `clientScopeSchema` was the only registered schema with no `sorts`
|
|
11
|
+
* allow-list, so rapiq fell back to a syntactic name check and handed an
|
|
12
|
+
* arbitrary `?sort=` key to `ORDER BY`. Declaring the allow-list requires
|
|
13
|
+
* every listed key to lead a real entity index; the two timestamp columns
|
|
14
|
+
* were the only ones missing theirs.
|
|
15
|
+
* - Makes `(provider_user_id, provider_id)` unique on
|
|
16
|
+
* `auth_identity_provider_accounts`. "One external identity belongs to one
|
|
17
|
+
* local user" was enforced only by a read-then-write in
|
|
18
|
+
* `IdentityProviderAccountManager`: no transaction, no row lock, and
|
|
19
|
+
* nothing behind it in the schema, so two concurrent completions for the
|
|
20
|
+
* same upstream subject could both observe "not linked" and both insert.
|
|
21
|
+
* After that the subject resolves to whichever row the database happens to
|
|
22
|
+
* order first. The column order matches the pre-existing non-unique index,
|
|
23
|
+
* so this is an in-place uniqueness flip under the same derived name
|
|
24
|
+
* rather than a rename.
|
|
25
|
+
*
|
|
26
|
+
* MySQL commits DDL implicitly, so `migrationsTransactionMode: 'all'` cannot
|
|
27
|
+
* roll a partial run back. A DROP followed by a CREATE would leave the table
|
|
28
|
+
* with no index of that name if the process died between them, and every
|
|
29
|
+
* later attempt would then fail at the DROP. One ALTER carrying both is
|
|
30
|
+
* atomic, so the uniqueness flip either applies or does not.
|
|
31
|
+
*
|
|
32
|
+
* Pre-existing duplicates abort the boot with an actionable message. They
|
|
33
|
+
* would abort it anyway, since `CREATE UNIQUE INDEX` fails on them; the
|
|
34
|
+
* check only decides whether the operator reads a readable sentence or a
|
|
35
|
+
* hash-named driver error.
|
|
36
|
+
*
|
|
37
|
+
* It runs BEFORE any DDL for the same implicit-commit reason: an abort
|
|
38
|
+
* after the two CREATE INDEX statements leaves them committed while the
|
|
39
|
+
* migration stays unapplied, so the operator's retry — after cleaning the
|
|
40
|
+
* duplicates — would die on `Duplicate key name` and never reach the flip.
|
|
41
|
+
* Nothing here writes before the check, so a refusal leaves the schema
|
|
42
|
+
* exactly as it was.
|
|
43
|
+
*
|
|
44
|
+
* Generated with `migration generate`; derived IDX_<hash> names, generated
|
|
45
|
+
* DDL untouched (the duplicate pre-check and the single-ALTER flip are
|
|
46
|
+
* hand-authored).
|
|
47
|
+
*/ var SortIndexesAndAccountUniqueness1786631686318 = class {
|
|
48
|
+
name = "SortIndexesAndAccountUniqueness1786631686318";
|
|
49
|
+
async up(queryRunner) {
|
|
50
|
+
const duplicates = await queryRunner.query(`
|
|
51
|
+
SELECT \`provider_id\`, \`provider_user_id\`, COUNT(*) AS \`count\`
|
|
52
|
+
FROM \`auth_identity_provider_accounts\`
|
|
53
|
+
GROUP BY \`provider_id\`, \`provider_user_id\`
|
|
54
|
+
HAVING COUNT(*) > 1
|
|
55
|
+
`);
|
|
56
|
+
if (duplicates.length > 0) throw new Error(`Identity-provider account uniqueness migration aborted: "auth_identity_provider_accounts" holds ${duplicates.length} duplicate (provider_id, provider_user_id) group(s). One external identity must belong to one local user. Merge or delete the conflicting rows manually before re-running.`);
|
|
57
|
+
await queryRunner.query(`
|
|
58
|
+
CREATE INDEX \`IDX_52f59535945c8cdbd62439bba5\` ON \`auth_client_scopes\` (\`created_at\`)
|
|
59
|
+
`);
|
|
60
|
+
await queryRunner.query(`
|
|
61
|
+
CREATE INDEX \`IDX_04264aebc8b6625b1da88e23df\` ON \`auth_client_scopes\` (\`updated_at\`)
|
|
62
|
+
`);
|
|
63
|
+
await queryRunner.query(`
|
|
64
|
+
ALTER TABLE \`auth_identity_provider_accounts\`
|
|
65
|
+
DROP INDEX \`IDX_ccf3fd36253755bd9a5f43c516\`,
|
|
66
|
+
ADD UNIQUE INDEX \`IDX_ccf3fd36253755bd9a5f43c516\` (\`provider_user_id\`, \`provider_id\`)
|
|
67
|
+
`);
|
|
68
|
+
}
|
|
69
|
+
async down(queryRunner) {
|
|
70
|
+
await queryRunner.query(`
|
|
71
|
+
ALTER TABLE \`auth_identity_provider_accounts\`
|
|
72
|
+
DROP INDEX \`IDX_ccf3fd36253755bd9a5f43c516\`,
|
|
73
|
+
ADD INDEX \`IDX_ccf3fd36253755bd9a5f43c516\` (\`provider_user_id\`, \`provider_id\`)
|
|
74
|
+
`);
|
|
75
|
+
await queryRunner.query(`
|
|
76
|
+
DROP INDEX \`IDX_04264aebc8b6625b1da88e23df\` ON \`auth_client_scopes\`
|
|
77
|
+
`);
|
|
78
|
+
await queryRunner.query(`
|
|
79
|
+
DROP INDEX \`IDX_52f59535945c8cdbd62439bba5\` ON \`auth_client_scopes\`
|
|
80
|
+
`);
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
//#endregion
|
|
84
|
+
export { SortIndexesAndAccountUniqueness1786631686318 };
|
|
85
|
+
|
|
86
|
+
//# sourceMappingURL=1786631686318-SortIndexesAndAccountUniqueness.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"1786631686318-SortIndexesAndAccountUniqueness.mjs","names":["SortIndexesAndAccountUniqueness1786631686318","name","up","queryRunner","duplicates","query","length","Error","down"],"sources":["../../../../../src/adapters/database/migrations/mysql/1786631686318-SortIndexesAndAccountUniqueness.ts"],"sourcesContent":["import type { MigrationInterface, QueryRunner } from 'typeorm';\n\n/**\n * Client-scope sort indexes (issue #3441) and identity-provider account\n * uniqueness (issue #3442).\n *\n * - Indexes `auth_client_scopes.created_at` and `updated_at`.\n * `clientScopeSchema` was the only registered schema with no `sorts`\n * allow-list, so rapiq fell back to a syntactic name check and handed an\n * arbitrary `?sort=` key to `ORDER BY`. Declaring the allow-list requires\n * every listed key to lead a real entity index; the two timestamp columns\n * were the only ones missing theirs.\n * - Makes `(provider_user_id, provider_id)` unique on\n * `auth_identity_provider_accounts`. \"One external identity belongs to one\n * local user\" was enforced only by a read-then-write in\n * `IdentityProviderAccountManager`: no transaction, no row lock, and\n * nothing behind it in the schema, so two concurrent completions for the\n * same upstream subject could both observe \"not linked\" and both insert.\n * After that the subject resolves to whichever row the database happens to\n * order first. The column order matches the pre-existing non-unique index,\n * so this is an in-place uniqueness flip under the same derived name\n * rather than a rename.\n *\n * MySQL commits DDL implicitly, so `migrationsTransactionMode: 'all'` cannot\n * roll a partial run back. A DROP followed by a CREATE would leave the table\n * with no index of that name if the process died between them, and every\n * later attempt would then fail at the DROP. One ALTER carrying both is\n * atomic, so the uniqueness flip either applies or does not.\n *\n * Pre-existing duplicates abort the boot with an actionable message. They\n * would abort it anyway, since `CREATE UNIQUE INDEX` fails on them; the\n * check only decides whether the operator reads a readable sentence or a\n * hash-named driver error.\n *\n * It runs BEFORE any DDL for the same implicit-commit reason: an abort\n * after the two CREATE INDEX statements leaves them committed while the\n * migration stays unapplied, so the operator's retry — after cleaning the\n * duplicates — would die on `Duplicate key name` and never reach the flip.\n * Nothing here writes before the check, so a refusal leaves the schema\n * exactly as it was.\n *\n * Generated with `migration generate`; derived IDX_<hash> names, generated\n * DDL untouched (the duplicate pre-check and the single-ALTER flip are\n * hand-authored).\n */\nexport class SortIndexesAndAccountUniqueness1786631686318 implements MigrationInterface {\n name = 'SortIndexesAndAccountUniqueness1786631686318';\n\n public async up(queryRunner: QueryRunner): Promise<void> {\n const duplicates = await queryRunner.query(`\n SELECT \\`provider_id\\`, \\`provider_user_id\\`, COUNT(*) AS \\`count\\`\n FROM \\`auth_identity_provider_accounts\\`\n GROUP BY \\`provider_id\\`, \\`provider_user_id\\`\n HAVING COUNT(*) > 1\n `);\n if (duplicates.length > 0) {\n throw new Error(\n `Identity-provider account uniqueness migration aborted: \"auth_identity_provider_accounts\" holds ${duplicates.length} ` +\n 'duplicate (provider_id, provider_user_id) group(s). One external identity must belong to one local user. ' +\n 'Merge or delete the conflicting rows manually before re-running.',\n );\n }\n\n await queryRunner.query(`\n CREATE INDEX \\`IDX_52f59535945c8cdbd62439bba5\\` ON \\`auth_client_scopes\\` (\\`created_at\\`)\n `);\n await queryRunner.query(`\n CREATE INDEX \\`IDX_04264aebc8b6625b1da88e23df\\` ON \\`auth_client_scopes\\` (\\`updated_at\\`)\n `);\n\n await queryRunner.query(`\n ALTER TABLE \\`auth_identity_provider_accounts\\`\n DROP INDEX \\`IDX_ccf3fd36253755bd9a5f43c516\\`,\n ADD UNIQUE INDEX \\`IDX_ccf3fd36253755bd9a5f43c516\\` (\\`provider_user_id\\`, \\`provider_id\\`)\n `);\n }\n\n public async down(queryRunner: QueryRunner): Promise<void> {\n await queryRunner.query(`\n ALTER TABLE \\`auth_identity_provider_accounts\\`\n DROP INDEX \\`IDX_ccf3fd36253755bd9a5f43c516\\`,\n ADD INDEX \\`IDX_ccf3fd36253755bd9a5f43c516\\` (\\`provider_user_id\\`, \\`provider_id\\`)\n `);\n await queryRunner.query(`\n DROP INDEX \\`IDX_04264aebc8b6625b1da88e23df\\` ON \\`auth_client_scopes\\`\n `);\n await queryRunner.query(`\n DROP INDEX \\`IDX_52f59535945c8cdbd62439bba5\\` ON \\`auth_client_scopes\\`\n `);\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CA,IAAaA,+CAAb,MAAaA;CACTC,OAAO;CAEP,MAAaC,GAAGC,aAAyC;EACrD,MAAMC,aAAa,MAAMD,YAAYE,MAAM;;;;;SAK1C;EACD,IAAID,WAAWE,SAAS,GACpB,MAAM,IAAIC,MACN,mGAAmGH,WAAWE,OAAO,2KAErH;EAIR,MAAMH,YAAYE,MAAM;;SAEvB;EACD,MAAMF,YAAYE,MAAM;;SAEvB;EAED,MAAMF,YAAYE,MAAM;;;;SAIvB;CACL;CAEA,MAAaG,KAAKL,aAAyC;EACvD,MAAMA,YAAYE,MAAM;;;;SAIvB;EACD,MAAMF,YAAYE,MAAM;;SAEvB;EACD,MAAMF,YAAYE,MAAM;;SAEvB;CACL;AACJ"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { MigrationInterface, QueryRunner } from 'typeorm';
|
|
2
|
+
/**
|
|
3
|
+
* Client-scope sort indexes (issue #3441) and identity-provider account
|
|
4
|
+
* uniqueness (issue #3442).
|
|
5
|
+
*
|
|
6
|
+
* - Indexes `auth_client_scopes.created_at` and `updated_at`.
|
|
7
|
+
* `clientScopeSchema` was the only registered schema with no `sorts`
|
|
8
|
+
* allow-list, so rapiq fell back to a syntactic name check and handed an
|
|
9
|
+
* arbitrary `?sort=` key to `ORDER BY`. Declaring the allow-list requires
|
|
10
|
+
* every listed key to lead a real entity index; the two timestamp columns
|
|
11
|
+
* were the only ones missing theirs.
|
|
12
|
+
* - Makes `(provider_user_id, provider_id)` unique on
|
|
13
|
+
* `auth_identity_provider_accounts`. "One external identity belongs to one
|
|
14
|
+
* local user" was enforced only by a read-then-write in
|
|
15
|
+
* `IdentityProviderAccountManager`: no transaction, no row lock, and
|
|
16
|
+
* nothing behind it in the schema, so two concurrent completions for the
|
|
17
|
+
* same upstream subject could both observe "not linked" and both insert.
|
|
18
|
+
* After that the subject resolves to whichever row the database happens to
|
|
19
|
+
* order first. The column order matches the pre-existing non-unique index,
|
|
20
|
+
* so this is an in-place uniqueness flip under the same derived name
|
|
21
|
+
* rather than a rename.
|
|
22
|
+
*
|
|
23
|
+
* Pre-existing duplicates abort the boot with an actionable message. They
|
|
24
|
+
* would abort it anyway, since `CREATE UNIQUE INDEX` fails on them; the
|
|
25
|
+
* check only decides whether the operator reads a readable sentence or a
|
|
26
|
+
* hash-named driver error.
|
|
27
|
+
*
|
|
28
|
+
* It runs before any DDL, matching the mysql half: postgres would roll the
|
|
29
|
+
* whole migration back on the abort, but keeping one order across both
|
|
30
|
+
* dialects means the refusal never depends on which one is reading it.
|
|
31
|
+
*
|
|
32
|
+
* Generated with `migration generate`; derived IDX_<hash> names, generated
|
|
33
|
+
* DDL untouched (the duplicate pre-check is hand-authored, and `down()`
|
|
34
|
+
* carries the hand-corrected column order — see
|
|
35
|
+
* .agents/references/typeorm.md).
|
|
36
|
+
*/
|
|
37
|
+
export declare class SortIndexesAndAccountUniqueness1786631686318 implements MigrationInterface {
|
|
38
|
+
name: string;
|
|
39
|
+
up(queryRunner: QueryRunner): Promise<void>;
|
|
40
|
+
down(queryRunner: QueryRunner): Promise<void>;
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=1786631686318-SortIndexesAndAccountUniqueness.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"1786631686318-SortIndexesAndAccountUniqueness.d.ts","sourceRoot":"","sources":["../../../../../src/adapters/database/migrations/postgres/1786631686318-SortIndexesAndAccountUniqueness.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAE/D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,qBAAa,4CAA6C,YAAW,kBAAkB;IACnF,IAAI,SAAkD;IAEzC,EAAE,CAAC,WAAW,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IA8B3C,IAAI,CAAC,WAAW,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;CAc7D"}
|
package/dist/adapters/database/migrations/postgres/1786631686318-SortIndexesAndAccountUniqueness.mjs
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import "node:path";
|
|
2
|
+
import "node:url";
|
|
3
|
+
import.meta.url;
|
|
4
|
+
//#region src/adapters/database/migrations/postgres/1786631686318-SortIndexesAndAccountUniqueness.ts
|
|
5
|
+
/**
|
|
6
|
+
* Client-scope sort indexes (issue #3441) and identity-provider account
|
|
7
|
+
* uniqueness (issue #3442).
|
|
8
|
+
*
|
|
9
|
+
* - Indexes `auth_client_scopes.created_at` and `updated_at`.
|
|
10
|
+
* `clientScopeSchema` was the only registered schema with no `sorts`
|
|
11
|
+
* allow-list, so rapiq fell back to a syntactic name check and handed an
|
|
12
|
+
* arbitrary `?sort=` key to `ORDER BY`. Declaring the allow-list requires
|
|
13
|
+
* every listed key to lead a real entity index; the two timestamp columns
|
|
14
|
+
* were the only ones missing theirs.
|
|
15
|
+
* - Makes `(provider_user_id, provider_id)` unique on
|
|
16
|
+
* `auth_identity_provider_accounts`. "One external identity belongs to one
|
|
17
|
+
* local user" was enforced only by a read-then-write in
|
|
18
|
+
* `IdentityProviderAccountManager`: no transaction, no row lock, and
|
|
19
|
+
* nothing behind it in the schema, so two concurrent completions for the
|
|
20
|
+
* same upstream subject could both observe "not linked" and both insert.
|
|
21
|
+
* After that the subject resolves to whichever row the database happens to
|
|
22
|
+
* order first. The column order matches the pre-existing non-unique index,
|
|
23
|
+
* so this is an in-place uniqueness flip under the same derived name
|
|
24
|
+
* rather than a rename.
|
|
25
|
+
*
|
|
26
|
+
* Pre-existing duplicates abort the boot with an actionable message. They
|
|
27
|
+
* would abort it anyway, since `CREATE UNIQUE INDEX` fails on them; the
|
|
28
|
+
* check only decides whether the operator reads a readable sentence or a
|
|
29
|
+
* hash-named driver error.
|
|
30
|
+
*
|
|
31
|
+
* It runs before any DDL, matching the mysql half: postgres would roll the
|
|
32
|
+
* whole migration back on the abort, but keeping one order across both
|
|
33
|
+
* dialects means the refusal never depends on which one is reading it.
|
|
34
|
+
*
|
|
35
|
+
* Generated with `migration generate`; derived IDX_<hash> names, generated
|
|
36
|
+
* DDL untouched (the duplicate pre-check is hand-authored, and `down()`
|
|
37
|
+
* carries the hand-corrected column order — see
|
|
38
|
+
* .agents/references/typeorm.md).
|
|
39
|
+
*/ var SortIndexesAndAccountUniqueness1786631686318 = class {
|
|
40
|
+
name = "SortIndexesAndAccountUniqueness1786631686318";
|
|
41
|
+
async up(queryRunner) {
|
|
42
|
+
const duplicates = await queryRunner.query(`
|
|
43
|
+
SELECT "provider_id", "provider_user_id", COUNT(*) AS "count"
|
|
44
|
+
FROM "auth_identity_provider_accounts"
|
|
45
|
+
GROUP BY "provider_id", "provider_user_id"
|
|
46
|
+
HAVING COUNT(*) > 1
|
|
47
|
+
`);
|
|
48
|
+
if (duplicates.length > 0) throw new Error(`Identity-provider account uniqueness migration aborted: "auth_identity_provider_accounts" holds ${duplicates.length} duplicate (provider_id, provider_user_id) group(s). One external identity must belong to one local user. Merge or delete the conflicting rows manually before re-running.`);
|
|
49
|
+
await queryRunner.query(`
|
|
50
|
+
CREATE INDEX "IDX_52f59535945c8cdbd62439bba5" ON "auth_client_scopes" ("created_at")
|
|
51
|
+
`);
|
|
52
|
+
await queryRunner.query(`
|
|
53
|
+
CREATE INDEX "IDX_04264aebc8b6625b1da88e23df" ON "auth_client_scopes" ("updated_at")
|
|
54
|
+
`);
|
|
55
|
+
await queryRunner.query(`
|
|
56
|
+
DROP INDEX "public"."IDX_ccf3fd36253755bd9a5f43c516"
|
|
57
|
+
`);
|
|
58
|
+
await queryRunner.query(`
|
|
59
|
+
CREATE UNIQUE INDEX "IDX_ccf3fd36253755bd9a5f43c516" ON "auth_identity_provider_accounts" ("provider_user_id", "provider_id")
|
|
60
|
+
`);
|
|
61
|
+
}
|
|
62
|
+
async down(queryRunner) {
|
|
63
|
+
await queryRunner.query(`
|
|
64
|
+
DROP INDEX "public"."IDX_ccf3fd36253755bd9a5f43c516"
|
|
65
|
+
`);
|
|
66
|
+
await queryRunner.query(`
|
|
67
|
+
CREATE INDEX "IDX_ccf3fd36253755bd9a5f43c516" ON "auth_identity_provider_accounts" ("provider_user_id", "provider_id")
|
|
68
|
+
`);
|
|
69
|
+
await queryRunner.query(`
|
|
70
|
+
DROP INDEX "public"."IDX_04264aebc8b6625b1da88e23df"
|
|
71
|
+
`);
|
|
72
|
+
await queryRunner.query(`
|
|
73
|
+
DROP INDEX "public"."IDX_52f59535945c8cdbd62439bba5"
|
|
74
|
+
`);
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
//#endregion
|
|
78
|
+
export { SortIndexesAndAccountUniqueness1786631686318 };
|
|
79
|
+
|
|
80
|
+
//# sourceMappingURL=1786631686318-SortIndexesAndAccountUniqueness.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"1786631686318-SortIndexesAndAccountUniqueness.mjs","names":["SortIndexesAndAccountUniqueness1786631686318","name","up","queryRunner","duplicates","query","length","Error","down"],"sources":["../../../../../src/adapters/database/migrations/postgres/1786631686318-SortIndexesAndAccountUniqueness.ts"],"sourcesContent":["import type { MigrationInterface, QueryRunner } from 'typeorm';\n\n/**\n * Client-scope sort indexes (issue #3441) and identity-provider account\n * uniqueness (issue #3442).\n *\n * - Indexes `auth_client_scopes.created_at` and `updated_at`.\n * `clientScopeSchema` was the only registered schema with no `sorts`\n * allow-list, so rapiq fell back to a syntactic name check and handed an\n * arbitrary `?sort=` key to `ORDER BY`. Declaring the allow-list requires\n * every listed key to lead a real entity index; the two timestamp columns\n * were the only ones missing theirs.\n * - Makes `(provider_user_id, provider_id)` unique on\n * `auth_identity_provider_accounts`. \"One external identity belongs to one\n * local user\" was enforced only by a read-then-write in\n * `IdentityProviderAccountManager`: no transaction, no row lock, and\n * nothing behind it in the schema, so two concurrent completions for the\n * same upstream subject could both observe \"not linked\" and both insert.\n * After that the subject resolves to whichever row the database happens to\n * order first. The column order matches the pre-existing non-unique index,\n * so this is an in-place uniqueness flip under the same derived name\n * rather than a rename.\n *\n * Pre-existing duplicates abort the boot with an actionable message. They\n * would abort it anyway, since `CREATE UNIQUE INDEX` fails on them; the\n * check only decides whether the operator reads a readable sentence or a\n * hash-named driver error.\n *\n * It runs before any DDL, matching the mysql half: postgres would roll the\n * whole migration back on the abort, but keeping one order across both\n * dialects means the refusal never depends on which one is reading it.\n *\n * Generated with `migration generate`; derived IDX_<hash> names, generated\n * DDL untouched (the duplicate pre-check is hand-authored, and `down()`\n * carries the hand-corrected column order — see\n * .agents/references/typeorm.md).\n */\nexport class SortIndexesAndAccountUniqueness1786631686318 implements MigrationInterface {\n name = 'SortIndexesAndAccountUniqueness1786631686318';\n\n public async up(queryRunner: QueryRunner): Promise<void> {\n const duplicates = await queryRunner.query(`\n SELECT \"provider_id\", \"provider_user_id\", COUNT(*) AS \"count\"\n FROM \"auth_identity_provider_accounts\"\n GROUP BY \"provider_id\", \"provider_user_id\"\n HAVING COUNT(*) > 1\n `);\n if (duplicates.length > 0) {\n throw new Error(\n `Identity-provider account uniqueness migration aborted: \"auth_identity_provider_accounts\" holds ${duplicates.length} ` +\n 'duplicate (provider_id, provider_user_id) group(s). One external identity must belong to one local user. ' +\n 'Merge or delete the conflicting rows manually before re-running.',\n );\n }\n\n await queryRunner.query(`\n CREATE INDEX \"IDX_52f59535945c8cdbd62439bba5\" ON \"auth_client_scopes\" (\"created_at\")\n `);\n await queryRunner.query(`\n CREATE INDEX \"IDX_04264aebc8b6625b1da88e23df\" ON \"auth_client_scopes\" (\"updated_at\")\n `);\n\n await queryRunner.query(`\n DROP INDEX \"public\".\"IDX_ccf3fd36253755bd9a5f43c516\"\n `);\n await queryRunner.query(`\n CREATE UNIQUE INDEX \"IDX_ccf3fd36253755bd9a5f43c516\" ON \"auth_identity_provider_accounts\" (\"provider_user_id\", \"provider_id\")\n `);\n }\n\n public async down(queryRunner: QueryRunner): Promise<void> {\n await queryRunner.query(`\n DROP INDEX \"public\".\"IDX_ccf3fd36253755bd9a5f43c516\"\n `);\n await queryRunner.query(`\n CREATE INDEX \"IDX_ccf3fd36253755bd9a5f43c516\" ON \"auth_identity_provider_accounts\" (\"provider_user_id\", \"provider_id\")\n `);\n await queryRunner.query(`\n DROP INDEX \"public\".\"IDX_04264aebc8b6625b1da88e23df\"\n `);\n await queryRunner.query(`\n DROP INDEX \"public\".\"IDX_52f59535945c8cdbd62439bba5\"\n `);\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCA,IAAaA,+CAAb,MAAaA;CACTC,OAAO;CAEP,MAAaC,GAAGC,aAAyC;EACrD,MAAMC,aAAa,MAAMD,YAAYE,MAAM;;;;;SAK1C;EACD,IAAID,WAAWE,SAAS,GACpB,MAAM,IAAIC,MACN,mGAAmGH,WAAWE,OAAO,2KAErH;EAIR,MAAMH,YAAYE,MAAM;;SAEvB;EACD,MAAMF,YAAYE,MAAM;;SAEvB;EAED,MAAMF,YAAYE,MAAM;;SAEvB;EACD,MAAMF,YAAYE,MAAM;;SAEvB;CACL;CAEA,MAAaG,KAAKL,aAAyC;EACvD,MAAMA,YAAYE,MAAM;;SAEvB;EACD,MAAMF,YAAYE,MAAM;;SAEvB;EACD,MAAMF,YAAYE,MAAM;;SAEvB;EACD,MAAMF,YAAYE,MAAM;;SAEvB;CACL;AACJ"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"refresh_token.d.ts","sourceRoot":"","sources":["../../../../../../src/adapters/http/adapters/oauth2/grant-types/refresh_token.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAA2B,wBAAwB,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"refresh_token.d.ts","sourceRoot":"","sources":["../../../../../../src/adapters/http/adapters/oauth2/grant-types/refresh_token.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAA2B,wBAAwB,EAAE,MAAM,eAAe,CAAC;AAQvF,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AAExC,OAAO,EAAE,uBAAuB,EAA4B,MAAM,8BAA8B,CAAC;AACjG,OAAO,KAAK,EACR,oBAAoB,EACpB,gBAAgB,EAChB,yBAAyB,EAC5B,MAAM,8BAA8B,CAAC;AACtC,OAAO,KAAK,EAAE,kCAAkC,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AACvF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAOnE,qBAAa,2BAA4B,SAAQ,uBAAwB,YAAW,gBAAgB;IAChG,SAAS,CAAC,mBAAmB,EAAG,yBAAyB,CAAC;IAE1D,SAAS,CAAC,oBAAoB,EAAG,oBAAoB,CAAC;IAEtD,SAAS,CAAC,eAAe,EAAG,gBAAgB,CAAC;IAE7C,SAAS,CAAC,iBAAiB,EAAE,iBAAiB,CAAC;gBAEnC,GAAG,EAAE,kCAAkC;IAS7C,cAAc,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAAC,wBAAwB,CAAC;CAqH5E"}
|
|
@@ -9,7 +9,7 @@ import { extractClientCredentialsFromRequest } from "./utils/credentials.mjs";
|
|
|
9
9
|
import { readRealmHint } from "./utils/realm.mjs";
|
|
10
10
|
import "./utils/index.mjs";
|
|
11
11
|
import { isClientPublic } from "@authup/core-kit";
|
|
12
|
-
import { OAuth2GrantError, OAuth2RequestError, OAuth2TokenGrant } from "@authup/specs";
|
|
12
|
+
import { OAuth2GrantError, OAuth2RequestError, OAuth2TokenGrant, isJWTError } from "@authup/specs";
|
|
13
13
|
import { getRequestHeader, getRequestIP } from "routup";
|
|
14
14
|
import { readRequestBody } from "@routup/basic/body";
|
|
15
15
|
//#region src/adapters/http/adapters/oauth2/grant-types/refresh_token.ts
|
|
@@ -31,7 +31,13 @@ var HTTPOAuth2RefreshTokenGrant = class extends OAuth2RefreshTokenGrant {
|
|
|
31
31
|
if (typeof refreshToken !== "string" || refreshToken.length === 0) throw OAuth2RequestError.malformed();
|
|
32
32
|
const { clientId, clientSecret } = await extractClientCredentialsFromRequest(event);
|
|
33
33
|
const certificateEvidence = await extractOAuth2ClientCertificateEvidence(event, this.certificateSource);
|
|
34
|
-
|
|
34
|
+
let payload;
|
|
35
|
+
try {
|
|
36
|
+
payload = await this.refreshTokenVerifier.verify(refreshToken, { skipActiveCheck: true });
|
|
37
|
+
} catch (e) {
|
|
38
|
+
if (isJWTError(e)) throw OAuth2GrantError.invalid();
|
|
39
|
+
throw e;
|
|
40
|
+
}
|
|
35
41
|
let client;
|
|
36
42
|
if (clientId) {
|
|
37
43
|
const realm = await this.realmRepository.resolve(readRealmHint(body), true);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"refresh_token.mjs","names":["isClientPublic","OAuth2GrantError","OAuth2RequestError","OAuth2TokenGrant","readRequestBody","getRequestHeader","getRequestIP","OAuth2RefreshTokenGrant","assertClientGrantAllowed","extractClientCredentialsFromRequest","extractOAuth2ClientCertificateEvidence","readRealmHint","HTTPOAuth2RefreshTokenGrant","clientAuthenticator","refreshTokenVerifier","realmRepository","certificateSource","ctx","tokenVerifier","runWithRequest","event","body","refreshToken","refresh_token","length","malformed","clientId","clientSecret","certificateEvidence","payload","verify","skipActiveCheck","client","realm","resolve","authenticate","id","client_id","invalid","undefined","REFRESH_TOKEN","confirmation","cnf","expectedThumbprint","validateCertificateEvidenceForBinding","resolveTokenBinding","realm_id","realmId","runWith","ipAddress","userAgent"],"sources":["../../../../../../src/adapters/http/adapters/oauth2/grant-types/refresh_token.ts"],"sourcesContent":["/*\n * Copyright (c) 2025-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 { type Client, isClientPublic } from '@authup/core-kit';\nimport type { OAuth2TokenConfirmation, OAuth2TokenGrantResponse } from '@authup/specs';\nimport { OAuth2GrantError, OAuth2RequestError, OAuth2TokenGrant } from '@authup/specs';\nimport { readRequestBody } from '@routup/basic/body';\nimport type { IAppEvent } from 'routup';\nimport { getRequestHeader, getRequestIP } from 'routup';\nimport { OAuth2RefreshTokenGrant, assertClientGrantAllowed } from '../../../../../core/index.ts';\nimport type {\n IOAuth2TokenVerifier,\n IRealmRepository,\n OAuth2ClientAuthenticator,\n} from '../../../../../core/index.ts';\nimport type { HTTPOAuth2RefreshTokenGrantContext, IHTTPOAuth2Grant } from './types.ts';\nimport type { CertificateSource } from '../../../request/index.ts';\nimport {\n extractClientCredentialsFromRequest,\n extractOAuth2ClientCertificateEvidence,\n readRealmHint,\n} from './utils/index.ts';\n\nexport class HTTPOAuth2RefreshTokenGrant extends OAuth2RefreshTokenGrant implements IHTTPOAuth2Grant {\n protected clientAuthenticator : OAuth2ClientAuthenticator;\n\n protected refreshTokenVerifier : IOAuth2TokenVerifier;\n\n protected realmRepository : IRealmRepository;\n\n protected certificateSource: CertificateSource;\n\n constructor(ctx: HTTPOAuth2RefreshTokenGrantContext) {\n super(ctx);\n\n this.clientAuthenticator = ctx.clientAuthenticator;\n this.refreshTokenVerifier = ctx.tokenVerifier;\n this.realmRepository = ctx.realmRepository;\n this.certificateSource = ctx.certificateSource ?? 'disabled';\n }\n\n async runWithRequest(event: IAppEvent): Promise<OAuth2TokenGrantResponse> {\n const body = await readRequestBody(event);\n const refreshToken = body?.refresh_token;\n if (typeof refreshToken !== 'string' || refreshToken.length === 0) {\n throw OAuth2RequestError.malformed();\n }\n\n const { clientId, clientSecret } = await extractClientCredentialsFromRequest(event);\n const certificateEvidence = await extractOAuth2ClientCertificateEvidence(event, this.certificateSource);\n\n // RFC 6749 §6: verify the refresh token first to learn its bound\n // client (if any), then enforce binding. Authenticate the requesting\n // client when credentials are present, or when the token requires\n // a client binding.\n //\n // skipActiveCheck: the durable auth_session_tokens row (not the cache\n // blocklist) is the refresh-token authority, so a replayed/consumed\n // token must reach runWith() to trigger family revocation instead of\n // being rejected here with JWT_INACTIVE.\n const payload = await this.refreshTokenVerifier.verify(refreshToken, { skipActiveCheck: true });\n\n let client: Client | undefined;\n\n if (clientId) {\n // A client authenticated itself. Resolve by the presented\n // id/secret (name resolution scoped by the realm hint — resolved\n // lazily so a bare refresh skips the SELECT) and enforce the\n // token↔client binding.\n const realm = await this.realmRepository.resolve(readRealmHint(body), true);\n\n client = await this.clientAuthenticator.authenticate(\n clientId,\n clientSecret,\n realm.id,\n certificateEvidence,\n );\n\n if (payload.client_id && payload.client_id !== client.id) {\n throw OAuth2GrantError.invalid();\n }\n } else if (payload.client_id) {\n // No client credentials were presented, but the token is bound to\n // a client. RFC 6749 §10.4: a public client cannot authenticate\n // (no secret) and is not required to — the bound identity is read\n // from the signed token (client_id is server-minted, so trusted)\n // and refresh-token rotation/replay detection is the abuse control.\n // A client with an authentication method MUST still authenticate.\n // Supplying the server-minted client id lets TLS clients prove\n // themselves with the request certificate, while a secret client\n // still fails because its secret is absent.\n client = await this.clientAuthenticator.authenticate(\n payload.client_id,\n undefined,\n undefined,\n certificateEvidence,\n );\n }\n\n if (client) {\n assertClientGrantAllowed(client, OAuth2TokenGrant.REFRESH_TOKEN);\n }\n\n let confirmation: OAuth2TokenConfirmation | undefined;\n if (payload.cnf) {\n const expectedThumbprint = payload.cnf['x5t#S256'];\n if (typeof expectedThumbprint !== 'string' || expectedThumbprint.length === 0) {\n throw OAuth2GrantError.invalid();\n }\n\n confirmation = this.clientAuthenticator.validateCertificateEvidenceForBinding(\n certificateEvidence,\n );\n if (confirmation['x5t#S256'] !== expectedThumbprint) {\n throw OAuth2GrantError.invalid();\n }\n } else if (client) {\n confirmation = this.clientAuthenticator.resolveTokenBinding(client, certificateEvidence);\n }\n\n // Realm parity for PUBLIC clients only: a public client may not refresh\n // a token whose realm differs from the (bound) client's own realm.\n // Kills cross-realm refresh tokens minted for a public `web` client\n // before the authorize-side realm gate existed. Authenticated clients\n // are exempt — the configured secret/certificate proves identity, and the\n // documented cross-realm password grant (UUID-identified user against a\n // master-realm client) depends on that exemption.\n if (\n client &&\n isClientPublic(client) &&\n payload.realm_id &&\n payload.realm_id !== client.realmId\n ) {\n throw OAuth2GrantError.invalid();\n }\n\n return this.runWith(payload, {\n confirmation,\n ipAddress: getRequestIP(event) ?? undefined,\n userAgent: getRequestHeader(event, 'user-agent') ?? undefined,\n });\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;AA2BA,IAAaY,8BAAb,cAAiDL,wBAAAA;CACnCM;CAEAC;CAEAC;CAEAC;CAEV,YAAYC,KAAyC;EACjD,MAAMA,GAAAA;EAEN,KAAKJ,sBAAsBI,IAAIJ;EAC/B,KAAKC,uBAAuBG,IAAIC;EAChC,KAAKH,kBAAkBE,IAAIF;EAC3B,KAAKC,oBAAoBC,IAAID,qBAAqB;CACtD;CAEA,MAAMG,eAAeC,OAAqD;EACtE,MAAMC,OAAO,MAAMjB,gBAAgBgB,KAAAA;EACnC,MAAME,eAAeD,MAAME;EAC3B,IAAI,OAAOD,iBAAiB,YAAYA,aAAaE,WAAW,GAC5D,MAAMtB,mBAAmBuB,UAAS;EAGtC,MAAM,EAAEC,UAAUC,iBAAiB,MAAMlB,oCAAoCW,KAAAA;EAC7E,MAAMQ,sBAAsB,MAAMlB,uCAAuCU,OAAO,KAAKJ,iBAAiB;EAWtG,MAAMa,UAAU,MAAM,KAAKf,qBAAqBgB,OAAOR,cAAc,EAAES,iBAAiB,KAAK,CAAA;EAE7F,IAAIC;EAEJ,IAAIN,UAAU;GAKV,MAAMO,QAAQ,MAAM,KAAKlB,gBAAgBmB,QAAQvB,cAAcU,IAAAA,GAAO,IAAA;GAEtEW,SAAS,MAAM,KAAKnB,oBAAoBsB,aACpCT,UACAC,cACAM,MAAMG,IACNR,mBAAAA;GAGJ,IAAIC,QAAQQ,aAAaR,QAAQQ,cAAcL,OAAOI,IAClD,MAAMnC,iBAAiBqC,QAAO;EAEtC,OAAO,IAAIT,QAAQQ,WAUfL,SAAS,MAAM,KAAKnB,oBAAoBsB,aACpCN,QAAQQ,WACRE,KAAAA,GACAA,KAAAA,GACAX,mBAAAA;EAIR,IAAII,QACAxB,yBAAyBwB,QAAQ7B,iBAAiBqC,aAAa;EAGnE,IAAIC;EACJ,IAAIZ,QAAQa,KAAK;GACb,MAAMC,qBAAqBd,QAAQa,IAAI;GACvC,IAAI,OAAOC,uBAAuB,YAAYA,mBAAmBnB,WAAW,GACxE,MAAMvB,iBAAiBqC,QAAO;GAGlCG,eAAe,KAAK5B,oBAAoB+B,sCACpChB,mBAAAA;GAEJ,IAAIa,aAAa,gBAAgBE,oBAC7B,MAAM1C,iBAAiBqC,QAAO;EAEtC,OAAO,IAAIN,QACPS,eAAe,KAAK5B,oBAAoBgC,oBAAoBb,QAAQJ,mBAAAA;EAUxE,IACII,UACAhC,eAAegC,MAAAA,KACfH,QAAQiB,YACRjB,QAAQiB,aAAad,OAAOe,SAE5B,MAAM9C,iBAAiBqC,QAAO;EAGlC,OAAO,KAAKU,QAAQnB,SAAS;GACzBY;GACAQ,WAAW3C,aAAac,KAAAA,KAAUmB,KAAAA;GAClCW,WAAW7C,iBAAiBe,OAAO,YAAA,KAAiBmB,KAAAA;EACxD,CAAA;CACJ;AACJ"}
|
|
1
|
+
{"version":3,"file":"refresh_token.mjs","names":["isClientPublic","OAuth2GrantError","OAuth2RequestError","OAuth2TokenGrant","isJWTError","readRequestBody","getRequestHeader","getRequestIP","OAuth2RefreshTokenGrant","assertClientGrantAllowed","extractClientCredentialsFromRequest","extractOAuth2ClientCertificateEvidence","readRealmHint","HTTPOAuth2RefreshTokenGrant","clientAuthenticator","refreshTokenVerifier","realmRepository","certificateSource","ctx","tokenVerifier","runWithRequest","event","body","refreshToken","refresh_token","length","malformed","clientId","clientSecret","certificateEvidence","payload","verify","skipActiveCheck","e","invalid","client","realm","resolve","authenticate","id","client_id","undefined","REFRESH_TOKEN","confirmation","cnf","expectedThumbprint","validateCertificateEvidenceForBinding","resolveTokenBinding","realm_id","realmId","runWith","ipAddress","userAgent"],"sources":["../../../../../../src/adapters/http/adapters/oauth2/grant-types/refresh_token.ts"],"sourcesContent":["/*\n * Copyright (c) 2025-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 { type Client, isClientPublic } from '@authup/core-kit';\nimport type { OAuth2TokenConfirmation, OAuth2TokenGrantResponse } from '@authup/specs';\nimport {\n OAuth2GrantError,\n OAuth2RequestError,\n OAuth2TokenGrant,\n isJWTError,\n} from '@authup/specs';\nimport { readRequestBody } from '@routup/basic/body';\nimport type { IAppEvent } from 'routup';\nimport { getRequestHeader, getRequestIP } from 'routup';\nimport { OAuth2RefreshTokenGrant, assertClientGrantAllowed } from '../../../../../core/index.ts';\nimport type {\n IOAuth2TokenVerifier,\n IRealmRepository,\n OAuth2ClientAuthenticator,\n} from '../../../../../core/index.ts';\nimport type { HTTPOAuth2RefreshTokenGrantContext, IHTTPOAuth2Grant } from './types.ts';\nimport type { CertificateSource } from '../../../request/index.ts';\nimport {\n extractClientCredentialsFromRequest,\n extractOAuth2ClientCertificateEvidence,\n readRealmHint,\n} from './utils/index.ts';\n\nexport class HTTPOAuth2RefreshTokenGrant extends OAuth2RefreshTokenGrant implements IHTTPOAuth2Grant {\n protected clientAuthenticator : OAuth2ClientAuthenticator;\n\n protected refreshTokenVerifier : IOAuth2TokenVerifier;\n\n protected realmRepository : IRealmRepository;\n\n protected certificateSource: CertificateSource;\n\n constructor(ctx: HTTPOAuth2RefreshTokenGrantContext) {\n super(ctx);\n\n this.clientAuthenticator = ctx.clientAuthenticator;\n this.refreshTokenVerifier = ctx.tokenVerifier;\n this.realmRepository = ctx.realmRepository;\n this.certificateSource = ctx.certificateSource ?? 'disabled';\n }\n\n async runWithRequest(event: IAppEvent): Promise<OAuth2TokenGrantResponse> {\n const body = await readRequestBody(event);\n const refreshToken = body?.refresh_token;\n if (typeof refreshToken !== 'string' || refreshToken.length === 0) {\n throw OAuth2RequestError.malformed();\n }\n\n const { clientId, clientSecret } = await extractClientCredentialsFromRequest(event);\n const certificateEvidence = await extractOAuth2ClientCertificateEvidence(event, this.certificateSource);\n\n // RFC 6749 §6: verify the refresh token first to learn its bound\n // client (if any), then enforce binding. Authenticate the requesting\n // client when credentials are present, or when the token requires\n // a client binding.\n //\n // skipActiveCheck: the durable auth_session_tokens row (not the cache\n // blocklist) is the refresh-token authority, so a replayed/consumed\n // token must reach runWith() to trigger family revocation instead of\n // being rejected here with JWT_INACTIVE.\n let payload : Awaited<ReturnType<typeof this.refreshTokenVerifier.verify>>;\n try {\n payload = await this.refreshTokenVerifier.verify(refreshToken, { skipActiveCheck: true });\n } catch (e) {\n // RFC 6749 §5.2: a refresh token the endpoint cannot accept is\n // `invalid_grant` (400). A verification failure raises a JWT\n // error, which answers 401 on a resource route (RFC 6750 §3.1),\n // and letting that status escape here would report a bad GRANT\n // as if the CLIENT had failed to authenticate. The branches\n // below already answer `invalid_grant` for a token bound to\n // another client, so this keeps one shape for the parameter.\n if (isJWTError(e)) {\n throw OAuth2GrantError.invalid();\n }\n\n throw e;\n }\n\n let client: Client | undefined;\n\n if (clientId) {\n // A client authenticated itself. Resolve by the presented\n // id/secret (name resolution scoped by the realm hint — resolved\n // lazily so a bare refresh skips the SELECT) and enforce the\n // token↔client binding.\n const realm = await this.realmRepository.resolve(readRealmHint(body), true);\n\n client = await this.clientAuthenticator.authenticate(\n clientId,\n clientSecret,\n realm.id,\n certificateEvidence,\n );\n\n if (payload.client_id && payload.client_id !== client.id) {\n throw OAuth2GrantError.invalid();\n }\n } else if (payload.client_id) {\n // No client credentials were presented, but the token is bound to\n // a client. RFC 6749 §10.4: a public client cannot authenticate\n // (no secret) and is not required to — the bound identity is read\n // from the signed token (client_id is server-minted, so trusted)\n // and refresh-token rotation/replay detection is the abuse control.\n // A client with an authentication method MUST still authenticate.\n // Supplying the server-minted client id lets TLS clients prove\n // themselves with the request certificate, while a secret client\n // still fails because its secret is absent.\n client = await this.clientAuthenticator.authenticate(\n payload.client_id,\n undefined,\n undefined,\n certificateEvidence,\n );\n }\n\n if (client) {\n assertClientGrantAllowed(client, OAuth2TokenGrant.REFRESH_TOKEN);\n }\n\n let confirmation: OAuth2TokenConfirmation | undefined;\n if (payload.cnf) {\n const expectedThumbprint = payload.cnf['x5t#S256'];\n if (typeof expectedThumbprint !== 'string' || expectedThumbprint.length === 0) {\n throw OAuth2GrantError.invalid();\n }\n\n confirmation = this.clientAuthenticator.validateCertificateEvidenceForBinding(\n certificateEvidence,\n );\n if (confirmation['x5t#S256'] !== expectedThumbprint) {\n throw OAuth2GrantError.invalid();\n }\n } else if (client) {\n confirmation = this.clientAuthenticator.resolveTokenBinding(client, certificateEvidence);\n }\n\n // Realm parity for PUBLIC clients only: a public client may not refresh\n // a token whose realm differs from the (bound) client's own realm.\n // Kills cross-realm refresh tokens minted for a public `web` client\n // before the authorize-side realm gate existed. Authenticated clients\n // are exempt — the configured secret/certificate proves identity, and the\n // documented cross-realm password grant (UUID-identified user against a\n // master-realm client) depends on that exemption.\n if (\n client &&\n isClientPublic(client) &&\n payload.realm_id &&\n payload.realm_id !== client.realmId\n ) {\n throw OAuth2GrantError.invalid();\n }\n\n return this.runWith(payload, {\n confirmation,\n ipAddress: getRequestIP(event) ?? undefined,\n userAgent: getRequestHeader(event, 'user-agent') ?? undefined,\n });\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;AAgCA,IAAaa,8BAAb,cAAiDL,wBAAAA;CACnCM;CAEAC;CAEAC;CAEAC;CAEV,YAAYC,KAAyC;EACjD,MAAMA,GAAAA;EAEN,KAAKJ,sBAAsBI,IAAIJ;EAC/B,KAAKC,uBAAuBG,IAAIC;EAChC,KAAKH,kBAAkBE,IAAIF;EAC3B,KAAKC,oBAAoBC,IAAID,qBAAqB;CACtD;CAEA,MAAMG,eAAeC,OAAqD;EACtE,MAAMC,OAAO,MAAMjB,gBAAgBgB,KAAAA;EACnC,MAAME,eAAeD,MAAME;EAC3B,IAAI,OAAOD,iBAAiB,YAAYA,aAAaE,WAAW,GAC5D,MAAMvB,mBAAmBwB,UAAS;EAGtC,MAAM,EAAEC,UAAUC,iBAAiB,MAAMlB,oCAAoCW,KAAAA;EAC7E,MAAMQ,sBAAsB,MAAMlB,uCAAuCU,OAAO,KAAKJ,iBAAiB;EAWtG,IAAIa;EACJ,IAAI;GACAA,UAAU,MAAM,KAAKf,qBAAqBgB,OAAOR,cAAc,EAAES,iBAAiB,KAAK,CAAA;EAC3F,SAASC,GAAG;GAQR,IAAI7B,WAAW6B,CAAAA,GACX,MAAMhC,iBAAiBiC,QAAO;GAGlC,MAAMD;EACV;EAEA,IAAIE;EAEJ,IAAIR,UAAU;GAKV,MAAMS,QAAQ,MAAM,KAAKpB,gBAAgBqB,QAAQzB,cAAcU,IAAAA,GAAO,IAAA;GAEtEa,SAAS,MAAM,KAAKrB,oBAAoBwB,aACpCX,UACAC,cACAQ,MAAMG,IACNV,mBAAAA;GAGJ,IAAIC,QAAQU,aAAaV,QAAQU,cAAcL,OAAOI,IAClD,MAAMtC,iBAAiBiC,QAAO;EAEtC,OAAO,IAAIJ,QAAQU,WAUfL,SAAS,MAAM,KAAKrB,oBAAoBwB,aACpCR,QAAQU,WACRC,KAAAA,GACAA,KAAAA,GACAZ,mBAAAA;EAIR,IAAIM,QACA1B,yBAAyB0B,QAAQhC,iBAAiBuC,aAAa;EAGnE,IAAIC;EACJ,IAAIb,QAAQc,KAAK;GACb,MAAMC,qBAAqBf,QAAQc,IAAI;GACvC,IAAI,OAAOC,uBAAuB,YAAYA,mBAAmBpB,WAAW,GACxE,MAAMxB,iBAAiBiC,QAAO;GAGlCS,eAAe,KAAK7B,oBAAoBgC,sCACpCjB,mBAAAA;GAEJ,IAAIc,aAAa,gBAAgBE,oBAC7B,MAAM5C,iBAAiBiC,QAAO;EAEtC,OAAO,IAAIC,QACPQ,eAAe,KAAK7B,oBAAoBiC,oBAAoBZ,QAAQN,mBAAAA;EAUxE,IACIM,UACAnC,eAAemC,MAAAA,KACfL,QAAQkB,YACRlB,QAAQkB,aAAab,OAAOc,SAE5B,MAAMhD,iBAAiBiC,QAAO;EAGlC,OAAO,KAAKgB,QAAQpB,SAAS;GACzBa;GACAQ,WAAW5C,aAAac,KAAAA,KAAUoB,KAAAA;GAClCW,WAAW9C,iBAAiBe,OAAO,YAAA,KAAiBoB,KAAAA;EACxD,CAAA;CACJ;AACJ"}
|
|
@@ -2,8 +2,8 @@ import "node:path";
|
|
|
2
2
|
import "node:url";
|
|
3
3
|
import.meta.url;
|
|
4
4
|
import { OAuth2RequestError } from "@authup/specs";
|
|
5
|
-
import { readRequestBody } from "@routup/basic/body";
|
|
6
5
|
import { AuthorizationHeaderType, parseAuthorizationHeader } from "hapic";
|
|
6
|
+
import { readRequestBody } from "@routup/basic/body";
|
|
7
7
|
//#region src/adapters/http/adapters/oauth2/grant-types/utils/credentials.ts
|
|
8
8
|
/**
|
|
9
9
|
* Extract client credentials from an OAuth2 token endpoint request.
|
|
@@ -2,9 +2,9 @@ import "node:path";
|
|
|
2
2
|
import "node:url";
|
|
3
3
|
import.meta.url;
|
|
4
4
|
import { OAuth2TokenGrant } from "@authup/specs";
|
|
5
|
+
import { AuthorizationHeaderType, parseAuthorizationHeader } from "hapic";
|
|
5
6
|
import { readRequestBody } from "@routup/basic/body";
|
|
6
7
|
import { useRequestQuery } from "@routup/basic/query";
|
|
7
|
-
import { AuthorizationHeaderType, parseAuthorizationHeader } from "hapic";
|
|
8
8
|
//#region src/adapters/http/adapters/oauth2/grant-types/utils/guess.ts
|
|
9
9
|
async function guessOauth2GrantTypeByRequest(event) {
|
|
10
10
|
const body = await readRequestBody(event);
|
|
@@ -3,6 +3,8 @@ import "node:url";
|
|
|
3
3
|
import.meta.url;
|
|
4
4
|
import { RECORD_QUERY_PARAMETERS, describeQuerySchema } from "../../../../../core/query/describe.mjs";
|
|
5
5
|
import { clientSchema } from "../../../../../core/entities/client/schema.mjs";
|
|
6
|
+
import { isSelfToken } from "../../../../../utils/self-id.mjs";
|
|
7
|
+
import "../../../../../utils/index.mjs";
|
|
6
8
|
import { OAuth2ScopeAttributesResolver } from "../../../../../core/oauth2/scope/resolver.mjs";
|
|
7
9
|
import "../../../../../core/index.mjs";
|
|
8
10
|
import { useRequestIdentity } from "../../../request/helpers/identity.mjs";
|
|
@@ -11,8 +13,6 @@ import { applyRouteRealmIDToBody, getRequestRealmID } from "../../../request/hel
|
|
|
11
13
|
import { useRequestScopes } from "../../../request/helpers/scopes.mjs";
|
|
12
14
|
import "../../../request/index.mjs";
|
|
13
15
|
import { ForceLoggedInMiddleware } from "../../../middleware/built-in/loggedin/module.mjs";
|
|
14
|
-
import { isSelfToken } from "../../../../../utils/self-id.mjs";
|
|
15
|
-
import "../../../../../utils/index.mjs";
|
|
16
16
|
import "../../../middleware/index.mjs";
|
|
17
17
|
import { EntityNotFoundError } from "@authup/errors";
|
|
18
18
|
import { OAuth2SubKind } from "@authup/specs";
|