The responder answered granted=true and the server still refused every client: Error non operator mode account "AUTH": attempted to use issuer_account nats_jwt::Token::new_user always sets issuer_account, which is an operator-mode field naming the account when a signing key rather than the account identity key signed the token. In server-config mode - what this module renders - its mere presence is fatal, and the account is named by the claims' aud instead. nats-jwt can express neither aud nor the omission, so the user JWT is now hand-built by the same signer as the response wrapper, and nats-jwt moves to dev-dependencies as the encoder's test oracle. Every unit test passed throughout: they assert fields that must be present, and the defect was a field that must be absent.
57 lines
2.2 KiB
TOML
57 lines
2.2 KiB
TOML
[package]
|
|
name = "swarm-nats-auth"
|
|
version.workspace = true
|
|
readme = "README.md"
|
|
edition.workspace = true
|
|
|
|
[[bin]]
|
|
name = "swarm-nats-auth"
|
|
path = "src/main.rs"
|
|
|
|
[dependencies]
|
|
anyhow.workspace = true
|
|
clap.workspace = true
|
|
reqwest.workspace = true
|
|
serde.workspace = true
|
|
serde_json.workspace = true
|
|
tokio.workspace = true
|
|
tracing.workspace = true
|
|
tracing-subscriber.workspace = true
|
|
# The NATS protocol client. `default-features = false` because the default set
|
|
# is broad - jetstream, kv, object-store, websockets, service - and a callout
|
|
# responder speaks none of them. What is named here is the whole requirement:
|
|
# the server generation we actually deploy, nkey auth, and a TLS backend.
|
|
# (Checked what dropping the defaults costs, the way `internal-logs` was once
|
|
# lost that way: nothing in the unused set is a diagnostic.)
|
|
async-nats = { version = "0.50", default-features = false, features = [
|
|
"server_2_14",
|
|
"nkeys",
|
|
"ring",
|
|
] }
|
|
# base64url for decoding the inbound request JWT. Already in the tree via
|
|
# nkeys; named directly because this crate uses it directly.
|
|
data-encoding = "2"
|
|
# StreamExt::next on the subscription. async-nats returns a Stream, not an
|
|
# iterator, and futures is already in the tree.
|
|
futures = "0.3"
|
|
# nkey seed handling + signing. The primitives (ed25519-dalek, data-encoding)
|
|
# are already in the tree, but the nkey *format* - ed25519 + base32 + CRC16 -
|
|
# is not, and hand-rolling a key format on an auth path is how you get a
|
|
# CRC bug nobody reviews.
|
|
nkeys = "0.4"
|
|
# The jti digest: base32hex(sha256(claims)) over every JWT this crate signs.
|
|
sha2 = "0.10"
|
|
|
|
[dev-dependencies]
|
|
# A TEST ORACLE, not part of the production path. Neither JWT this crate emits
|
|
# is expressible through it - `Claims` has no `aud`, which the response wrapper
|
|
# needs (the server id) and the user token needs (the account name), and
|
|
# `Token::new_user` always sets `issuer_account`, which a non-operator server
|
|
# rejects outright. So both are hand-built, and this crate is what the encoder
|
|
# is checked *against*: `respond::tests::hand_built_matches_the_reference`
|
|
# builds a user token both ways and requires byte equality, on the one shape
|
|
# nats-jwt does model.
|
|
nats-jwt = "0.3"
|
|
|
|
[lints]
|
|
workspace = true
|