diff --git a/deploy/dev-jwt-issuer-policies.json b/deploy/dev-jwt-issuer-policies.json new file mode 100644 index 0000000..7da612a --- /dev/null +++ b/deploy/dev-jwt-issuer-policies.json @@ -0,0 +1,47 @@ +[ + { + "issuer": "https://api.topcoder-dev.com", + "algorithm": "RS256", + "audience": "https://api.topcoder-dev.com/v6", + "jwksUri": "https://api.topcoder-dev.com/v6/authorizations/.well-known/jwks.json" + }, + { + "issuer": "https://auth.topcoder-dev.com/", + "algorithm": "RS256", + "audience": "BXWXUWnilVUPdN01t2Se29Tw2ZYNGZvH", + "jwksUri": "https://auth.topcoder-dev.com/.well-known/jwks.json" + }, + { + "issuer": "https://topcoder-dev.auth0.com/", + "algorithm": "RS256", + "audience": [ + "BXWXUWnilVUPdN01t2Se29Tw2ZYNGZvH", + "https://m2m.topcoder-dev.com/" + ], + "jwksUri": "https://topcoder-dev.auth0.com/.well-known/jwks.json" + }, + { + "issuer": "https://keycloak.topcoder-dev.com/realms/topcoder-m2m-dev", + "algorithm": "RS256", + "audience": "https://m2m.topcoder-dev.com/", + "jwksUri": "https://keycloak.topcoder-dev.com/realms/topcoder-m2m-dev/protocol/openid-connect/certs" + }, + { + "issuer": "https://testsachin.topcoder-dev.com/", + "algorithm": "RS256", + "audience": [ + "BXWXUWnilVUPdN01t2Se29Tw2ZYNGZvH", + "https://m2m.topcoder-dev.com/" + ], + "jwksUri": "https://testsachin.topcoder-dev.com/.well-known/jwks.json" + }, + { + "issuer": "https://test-sachin-rs256.auth0.com/", + "algorithm": "RS256", + "audience": [ + "BXWXUWnilVUPdN01t2Se29Tw2ZYNGZvH", + "https://m2m.topcoder-dev.com/" + ], + "jwksUri": "https://test-sachin-rs256.auth0.com/.well-known/jwks.json" + } +] diff --git a/docs/identity-rs256-dev.md b/docs/identity-rs256-dev.md new file mode 100644 index 0000000..121d58e --- /dev/null +++ b/docs/identity-rs256-dev.md @@ -0,0 +1,11 @@ +# Identity RS256 preparation for dev + +This PR pins tc-core-library-js 4.0.0-rc.4 at commit `c7c8fab502b7152dd06b1ce46cdb703e0e13b357`. It requires explicit issuer policies and retains verified-email and identity-denylist enforcement. + +The public settings are staged in dev Parameter Store under `/config/identity-rs256-dev-staged/`; running services do not reference that namespace. The checked-in JSON is a reviewed configuration proposal, not an automatically applied deployment change. + +Before merging/deploying, coordinate with Identity and all token consumers. Set `JWT_ISSUER_POLICIES` to the JSON in `deploy/dev-jwt-issuer-policies.json`, retaining the service's machine audience and authorization checks. Merely adding `AUTH_SECRET` no longer enables HMAC trust. If a transition needs HS256, configure only that exact issuer with a finite UTC retirement deadline, then replace it with RS256 at the coordinated cutover. Never accept both algorithms for one issuer. + +Publish the Identity public key first; then test fresh login, expiry/refresh, logout, cross-app access, human authorization, machine authorization, wrong-audience rejection and legacy-HMAC rejection. Remove AUTH_SECRET only from public-key-only API verifiers; keep separate keys for application proofs, cursors, and independent local-login tokens. Existing browser sessions continue to use Auth0; do not put Identity-issued tokens into the Accounts connector cookie without implementing an Identity-aware refresh flow. + +Production is not changed. This dev policy intentionally does not trust the production Topcoder issuer. Do not merge this into production without its separately reviewed environment policy and key. diff --git a/package.json b/package.json index 1253013..39e55ed 100644 --- a/package.json +++ b/package.json @@ -51,7 +51,7 @@ "qs": "6.17.1", "reflect-metadata": "^0.2.2", "rxjs": "^7.8.2", - "tc-core-library-js": "https://codeload.github.com/topcoder-platform/tc-core-library-js/tar.gz/c2df92b2227089909ab6e229df0ec6b658bb431a", + "tc-core-library-js": "https://codeload.github.com/topcoder-platform/tc-core-library-js/tar.gz/c7c8fab502b7152dd06b1ce46cdb703e0e13b357", "uuid": "^14.0.3", "winston": "^3.19.0" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index efa3a1c..b61a76e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -31,7 +31,7 @@ overrides: browserslist: 4.28.8 axios@<1: 0.34.0 axios@>=1: 1.21.0 - tc-core-library-js: https://codeload.github.com/topcoder-platform/tc-core-library-js/tar.gz/c2df92b2227089909ab6e229df0ec6b658bb431a + tc-core-library-js: https://codeload.github.com/topcoder-platform/tc-core-library-js/tar.gz/c7c8fab502b7152dd06b1ce46cdb703e0e13b357 deepmerge-ts: 8.0.0 defu: 6.1.7 effect@^3: 3.22.0 @@ -128,8 +128,8 @@ importers: specifier: ^7.8.2 version: 7.8.2 tc-core-library-js: - specifier: https://codeload.github.com/topcoder-platform/tc-core-library-js/tar.gz/c2df92b2227089909ab6e229df0ec6b658bb431a - version: https://codeload.github.com/topcoder-platform/tc-core-library-js/tar.gz/c2df92b2227089909ab6e229df0ec6b658bb431a(supports-color@8.1.1) + specifier: https://codeload.github.com/topcoder-platform/tc-core-library-js/tar.gz/c7c8fab502b7152dd06b1ce46cdb703e0e13b357 + version: https://codeload.github.com/topcoder-platform/tc-core-library-js/tar.gz/c7c8fab502b7152dd06b1ce46cdb703e0e13b357(supports-color@8.1.1) uuid: specifier: ^14.0.3 version: 14.0.3 @@ -4142,9 +4142,9 @@ packages: tar-stream@3.1.7: resolution: {integrity: sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==} - tc-core-library-js@https://codeload.github.com/topcoder-platform/tc-core-library-js/tar.gz/c2df92b2227089909ab6e229df0ec6b658bb431a: - resolution: {gitHosted: true, integrity: sha512-n+4KUOeV4LEIsTI/R216dBc6bUkbSyO/2O0LpoY3Hk7eqKsRQFUHloB3y0hfK/v1rzf8qYQxTdv8ikeRGBn4pQ==, tarball: https://codeload.github.com/topcoder-platform/tc-core-library-js/tar.gz/c2df92b2227089909ab6e229df0ec6b658bb431a} - version: 4.0.0-rc.2.1 + tc-core-library-js@https://codeload.github.com/topcoder-platform/tc-core-library-js/tar.gz/c7c8fab502b7152dd06b1ce46cdb703e0e13b357: + resolution: {tarball: https://codeload.github.com/topcoder-platform/tc-core-library-js/tar.gz/c7c8fab502b7152dd06b1ce46cdb703e0e13b357} + version: 4.0.0-rc.4 engines: {node: '>=22.13'} terser-webpack-plugin@5.6.1: @@ -8974,7 +8974,7 @@ snapshots: - bare-abort-controller - react-native-b4a - tc-core-library-js@https://codeload.github.com/topcoder-platform/tc-core-library-js/tar.gz/c2df92b2227089909ab6e229df0ec6b658bb431a(supports-color@8.1.1): + tc-core-library-js@https://codeload.github.com/topcoder-platform/tc-core-library-js/tar.gz/c7c8fab502b7152dd06b1ce46cdb703e0e13b357(supports-color@8.1.1): dependencies: '@types/jsonwebtoken': 9.0.10 jsonwebtoken: 9.0.3 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 32a041c..7ad78f9 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -47,7 +47,7 @@ overrides: browserslist: 4.28.8 axios@<1: 0.34.0 axios@>=1: 1.21.0 - tc-core-library-js: https://codeload.github.com/topcoder-platform/tc-core-library-js/tar.gz/c2df92b2227089909ab6e229df0ec6b658bb431a + tc-core-library-js: https://codeload.github.com/topcoder-platform/tc-core-library-js/tar.gz/c7c8fab502b7152dd06b1ce46cdb703e0e13b357 deepmerge-ts: 8.0.0 defu: 6.1.7 effect@^3: 3.22.0 diff --git a/src/shared/modules/global/jwt.service.spec.ts b/src/shared/modules/global/jwt.service.spec.ts index d2b8351..2d83afa 100644 --- a/src/shared/modules/global/jwt.service.spec.ts +++ b/src/shared/modules/global/jwt.service.spec.ts @@ -26,11 +26,25 @@ function signToken(payload: Record): string { describe('JwtService', () => { let service: JwtService; + const previousPolicies = process.env.JWT_ISSUER_POLICIES; + afterEach(() => { + if (previousPolicies === undefined) delete process.env.JWT_ISSUER_POLICIES; + else process.env.JWT_ISSUER_POLICIES = previousPolicies; + }); beforeEach(() => { process.env.AUTH_SECRET = 'test-secret-with-at-least-32-bytes-long'; process.env.VALID_ISSUERS = JSON.stringify(['https://issuer.test/']); process.env.AUTH0_AUDIENCE = 'api'; + process.env.JWT_ISSUER_POLICIES = JSON.stringify([ + { + issuer: 'https://issuer.test/', + algorithm: 'HS256', + audience: 'api', + legacyHs256Until: new Date(Date.now() + 3_600_000).toISOString(), + }, + { issuer: 'https://machine.test/', algorithm: 'RS256', audience: 'api' }, + ]); service = new JwtService(); service.onModuleInit(); }); @@ -89,7 +103,7 @@ describe('JwtService', () => { { algorithm: 'RS256', keyid: 'test-key', - issuer: 'https://issuer.test/', + issuer: 'https://machine.test/', audience: 'api', expiresIn: 300, },