oauth: parse repo scopes that name collections with the collection parameter #
repo?collection=app.example.profile&collection=app.example.post failed NSID validation because only the text before ? was read as the collection. The permission spec gives that exact string as valid (https://atproto.com/specs/permission#repo)
lexicon, oauth: follow the spec for permission-set rpc audiences #
A permission set with "aud": "*" failed to parse ("regex failure"), because the field was typed as a DID service reference. Expansion was also too permissive: no audience, or inheritAud with nothing to inherit, widened to every service. The spec (https://atproto.com/specs/permission#rpc) allows *, forbids DID references inside a set, and says those cases are invalid and ignored.
oauth: always write the audience of rpc scopes #
to_string_normalized dropped ?aud=*, writing rpc:. The spec says aud is "always required in granular string representation", and the reference server ignores rpc scopes without it, so these scopes were silently never granted.
common, axum: use the #atproto verification method as the signing key #
DidDocument::atproto_multikey and jacquard-axum's extract_signing_key took the first Multikey (axum: any first key). The DID spec (https://atproto.com/specs/did) says the signing key is the entry whose id ends in #atproto, typed Multikey and controlled by the DID, and that others are ignored. real example: did:web:offbeatwit.ch lists #atproto_old first, so its commits were verified against the old key and rejected.