Skip to content

feat: add support for asymmetrical url signing keys, auth style key rotation and well-known - #1257

Open
itslenny wants to merge 4 commits into
masterfrom
lenny/jwks-support-standby-key-and-asymmetric-keys
Open

feat: add support for asymmetrical url signing keys, auth style key rotation and well-known#1257
itslenny wants to merge 4 commits into
masterfrom
lenny/jwks-support-standby-key-and-asymmetric-keys

Conversation

@itslenny

@itslenny itslenny commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

What kind of change does this PR introduce?

Feature

What is the current behavior?

  • Only supports symmetric (HMAC) url signing keys
  • No way to create standby keys or swap them (similar to how auth key rotation works)
  • No way to list tenant jwks
  • JWK/JWT includes the mutable kind as a prefix in the kid - this makes swapping keys problematic

What is the new behavior?

  • Remove kind prefix from kid
  • Support generating/using asymmetrical signing keys (ECDSA)
  • Add endpoints to support "auth style" key rotation
    • Create standby signing keys
    • Swap standby signing keys to active (used to sign URLs via api)
    • List jwks
  • Add public .well-known/jwks.json so asymmetric keys can be validated at the gateway

@itslenny
itslenny requested a review from a team as a code owner July 23, 2026 19:25
@blacksmith-sh

This comment has been minimized.

@coveralls

coveralls commented Jul 23, 2026

Copy link
Copy Markdown

Coverage Report for CI Build 32157055349

Coverage increased (+0.1%) to 81.29%

Details

  • Coverage increased (+0.1%) from the base build.
  • Patch coverage: 6 uncovered changes across 4 files (118 of 124 lines covered, 95.16%).
  • 1 coverage regression across 1 file.

Uncovered Changes

File Changed Covered %
src/storage/events/jwks/jwks-create-signing-secret.ts 2 0 0.0%
src/test/utils/config-change-awaiter.ts 12 10 83.33%
src/internal/auth/jwks/manager.ts 22 21 95.45%
src/internal/auth/jwks/store-pg.ts 15 14 93.33%
Total (13 files) 124 118 95.16%

Coverage Regressions

1 previously-covered line in 1 file lost coverage.

File Lines Losing Coverage Coverage
src/http/routes/s3/index.ts 1 87.42%

Coverage Stats

Coverage Status
Relevant Lines: 13102
Covered Lines: 11079
Line Coverage: 84.56%
Relevant Branches: 7764
Covered Branches: 5883
Branch Coverage: 75.77%
Branches in Coverage %: Yes
Coverage Strength: 601.55 hits per line

💛 - Coveralls

claude[bot]

This comment was marked as outdated.

@itslenny
itslenny force-pushed the lenny/jwks-support-standby-key-and-asymmetric-keys branch 5 times, most recently from 868168d to 385ef32 Compare July 29, 2026 19:31
Comment thread src/internal/auth/jwks/store-pg.ts
@itslenny
itslenny force-pushed the lenny/jwks-support-standby-key-and-asymmetric-keys branch from 385ef32 to 81b3ff4 Compare July 31, 2026 21:05
Comment thread src/storage/events/jwks/jwks-roll-url-signing-key.ts Outdated
@itslenny
itslenny force-pushed the lenny/jwks-support-standby-key-and-asymmetric-keys branch 3 times, most recently from 911b0a0 to 22eead5 Compare August 4, 2026 20:47
Comment thread src/internal/auth/jwt.ts Outdated
Comment thread src/internal/auth/jwt.ts Outdated
Comment thread src/internal/auth/jwks/manager.ts
Comment thread src/internal/database/tenant.ts
Comment thread src/app.ts
Comment thread src/app.ts Outdated
Comment thread src/internal/auth/jwks/manager.ts Outdated
@itslenny
itslenny force-pushed the lenny/jwks-support-standby-key-and-asymmetric-keys branch from 22eead5 to 5d8582b Compare August 7, 2026 17:17
Comment thread src/app.ts
@itslenny
itslenny force-pushed the lenny/jwks-support-standby-key-and-asymmetric-keys branch from 5d8582b to 244508d Compare August 7, 2026 17:48
@itslenny
itslenny requested a review from ferhatelmas August 7, 2026 17:53
Comment thread src/http/routes/admin/jwks.ts Outdated
Comment thread src/http/routes/admin/jwks.ts Outdated
Comment thread src/http/routes/admin/jwks.ts Outdated
Comment thread src/internal/auth/jwks/manager.ts
Comment thread src/app.ts
Comment thread src/app.ts
@itslenny
itslenny force-pushed the lenny/jwks-support-standby-key-and-asymmetric-keys branch from 244508d to f3ee36f Compare August 11, 2026 16:47
Comment thread src/internal/auth/jwks/manager.ts Outdated
@itslenny
itslenny force-pushed the lenny/jwks-support-standby-key-and-asymmetric-keys branch from f3ee36f to 7168637 Compare August 11, 2026 17:11
@itslenny
itslenny requested a review from ferhatelmas August 11, 2026 17:13
Comment thread src/internal/auth/jwt.ts Outdated
Comment thread src/internal/database/tenant.ts Outdated
Comment thread src/internal/auth/jwt.ts
Comment thread src/internal/auth/jwt.ts Outdated
@itslenny
itslenny force-pushed the lenny/jwks-support-standby-key-and-asymmetric-keys branch from 7168637 to 36ef6d4 Compare August 13, 2026 13:55
@itslenny
itslenny requested a review from ferhatelmas August 13, 2026 13:59
Comment thread src/internal/auth/jwks/kid.ts
Comment thread src/storage/events/jwks/jwks-create-signing-secret.ts
Comment thread src/storage/events/jwks/jwks-create-signing-secret.ts Outdated
Comment thread src/internal/auth/jwks/store-pg.ts
@itslenny
itslenny requested a review from ferhatelmas August 14, 2026 19:48
@itslenny
itslenny force-pushed the lenny/jwks-support-standby-key-and-asymmetric-keys branch 2 times, most recently from b793725 to 1ac6475 Compare August 14, 2026 20:40
@itslenny
itslenny force-pushed the lenny/jwks-support-standby-key-and-asymmetric-keys branch from 1ac6475 to 6840d1d Compare August 18, 2026 15:52
Comment thread src/internal/auth/jwt.ts
Comment on lines 530 to 532
const signingSecret = JWT_HMAC_ALGOS.includes(alg)
? await getPreparedJWTSigningKey(secret, alg)
: await importJWK(secret)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this becomes statistically true with the feature, we should use the cached one unconditionally, it already handles internally

Comment on lines +180 to +182
if (typeof urlSigningKey !== 'string' && kid === urlSigningKey.kid) {
return reply.status(409).send({ error: 'Cannot deactivate the current url signing key' })
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: shall we add active:true into condition as noop?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

noting, this is using cached version, should we keep this check in db layer just in case?

if (typeof urlSigningKey !== 'string' && kid === urlSigningKey.kid) {
return reply.status(409).send({ error: 'Cannot deactivate the current url signing key' })
}
const result = await jwksManager.toggleJwkActive(tenantId, kid, active)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: this can throw 500 if already existing active. By normal client, it won't be the case but might be better to catch and return 400/409

}
}

interface JwksGenerateStandbyRequestInterface extends RequestGenericInterface {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: this seems same with JwksRollRequestInterface

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants