Repository navigation
Accept a JWT audience sent as a string, not only an array - #16
Merged
Merged
Conversation
AccessClaims typed `aud` as Vec<String>. RFC 7519 §4.1.3 allows either a single string or an array, and Cloudflare Access uses the string form when a token is scoped to one application — which is the ordinary case. So the claims failed to deserialize against every real token. The failure was badly disguised. It happened while parsing the claims, inside the same `decode` call that verifies the signature, so it surfaced as "Invalid Access token: JSON error: invalid type: string … expected a sequence". That reads like a rejected credential, and sent the first caller looking at service tokens and Access policies — all of which were correct. Access had authenticated the request and handed us a valid assertion; this code then declined to parse it. The audience is still checked by Validation::set_audience, which handles both shapes itself. This field only needs to deserialize, so it now normalises one-or-many to a list and nothing downstream changes. A number or an object is still rejected: tolerating the two shapes the spec allows is not the same as tolerating anything. Found by the first real request through Access, from the vetting Worker's service token. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The value was a real Access AUD tag from the deployment that surfaced this bug. It is not a credential — it identifies an Access application and cannot mint, sign or forge anything — but it is deployment configuration and this repository is public, so it has no business being here when any 64-character string proves the same point. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
.vscode/settings.json held only Peacock colour customisations — a per-person choice about what tint one editor window has. Committing it pushes one contributor's theme onto everyone who opens the repository, and the file churns whenever Peacock runs. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The field was documented as carrying "the token's name". Cloudflare sets it to the service token's Client ID (CF-Access-Client-Id), and CF_ACCESS_ALLOWED_SERVICE_TOKENS is matched against it — so an operator following the comment would fill the allowlist with dashboard names that can never match, and the rejection would name a token that looks entirely correct. Nothing changes at runtime; the code was already comparing against the right value. Only the comments were wrong, which is the kind of wrong that surfaces as a misconfigured deployment rather than a failing test. Also records why the audience fix accepts both shapes: Cloudflare's own documentation shows `aud` as an array, and the deployment that hit this sent a string. The RFC permits either, so the parser takes either rather than trusting one source over the other. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
aitorres
approved these changes
Aug 28, 2026
northernpolaris
approved these changes
Aug 28, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follow-up to #14. The endpoint it added has never successfully authenticated a real request — this is why.
What happens
AccessClaimstypesaudasVec<String>. RFC 7519 §4.1.3 allowsaudto be either a single string or an array of strings, and Cloudflare Access uses the string form when a token is scoped to one application — the ordinary case. So the claims fail to deserialize against every real token:Why it was hard to read
The failure happens while parsing the claims, inside the same
decodecall that verifies the signature — so it surfaces as "Invalid Access token". That reads like a rejected credential, and sent the first caller checking service tokens, Access policies andCF_ACCESS_ALLOWED_SERVICE_TOKENS, all of which were correct. Access had authenticated the request and handed over a valid assertion; this code then declined to parse it.The fix
auddeserializes from one-or-many into a list. Nothing downstream changes, and the security property is untouched: the audience is checked byValidation::set_audience, which handles both shapes itself. This field only ever needed to deserialize.A number or an object is still rejected — tolerating the two shapes the spec allows is not the same as tolerating anything.
Tests
Three: string form, array form, and neither. Placeholder audience values throughout. 48 unit + 3 integration passing, clippy and fmt clean.