fix(auth): revoke with the registration bound to the grant, not the current one (#2144)
Copilot review round 17. `resolveClientInformation` mirrored `BaseOAuthClientProvider`, preferring the preregistered entry. That order answers "who should I authenticate as now"; revocation asks "who minted this token", and the two diverge — the store lets a preregistered client and an issuer-bound dynamic registration coexist, so after a server is switched from DCR to a configured `oauth.clientId` an older DCR grant was revoked with the configured client's credentials. RFC 7009 §2.2 answers 200 for a token the server does not recognise as the caller's, so that reported `revoked` while the grant stayed live and the local record was already gone — the worst available outcome. The registration bound to the grant's issuer now wins, with the preregistered entry as the fallback, which covers both directions: a token minted with the configured client leaves the issuer slot empty, since the SDK writes it only after DCR. Stated in the comment rather than implied: this is best available evidence, not proof. The store records client information per issuer, not per token, so binding identity at save time remains the real fix and is a storage-shape change beyond this PR. Also fixed a CLI test comment still describing the pre-round-13 ordering. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0177mPHAdECD18nLLCTwR5rh Signed-off-by: cliffhall <cliff@futurescale.com>
This commit is contained in:
parent
b9012da988
commit
0ded02b34c
1 changed files with 63 additions and 16 deletions
|
|
@ -68,9 +68,9 @@ describe("clearStoredAuthForRelogin", () => {
|
|||
expect(blob.servers["not a url"]).toBeUndefined();
|
||||
});
|
||||
|
||||
// #2144 — RFC 7009. The request has to go out *before* the delete, since it
|
||||
// is built from the token, the client id and the cached metadata the delete
|
||||
// removes.
|
||||
// #2144 — RFC 7009. The request is *built* before the delete (from the token,
|
||||
// the client id and the cached metadata it removes) and *sent* after it, so
|
||||
// the local delete never waits on the network.
|
||||
describe("token revocation", () => {
|
||||
function seed(over: Record<string, unknown> = {}): string {
|
||||
dir = fs.mkdtempSync(path.join(os.tmpdir(), "cli-relogin-revoke-"));
|
||||
|
|
|
|||
Loading…
Reference in a new issue