Sender
A sender is an identity an auth provider can authenticate as. One provider, many users: admin, read-only viewer, a user in another tenant, a service account.
Without senders, testing “does this endpoint reject a non-admin?” means reconfiguring your auth or keeping a second provider around. With them it is a dropdown.
senders: - id: admin@example.com label: Staging admin tenant: acme secretRef: users-api.admin.PASSWORD vars: role: admin| Field | Meaning |
|---|---|
id | Required. The identifier the provider authenticates with — a username, an email, a subject id. |
label | Human name shown in the picker. |
tenant | An informational label for grouping in the UI. It is not a selection axis on its own. |
secretRef | The name of this identity’s keychain entry. Never a value. |
vars | Non-secret per-sender values, available as {{var}} while the token is being resolved. |
A provider with no senders has a single implicit identity, and the script receives sender as
null.
Where senders come from
Section titled “Where senders come from”They are rows in the provider file, and there are three ways they get there.
Typed in. The manual form takes an id, a label, and — where the provider signs in per sender — a password, which goes to the keychain under a name the file then references.
Fetched from the identity provider. Clerk, Firebase and the rest can list their own users, so the picker shows real accounts rather than asking you to remember an email. A Firebase project configured with a service account can list users this way too. Refreshing re-reads labels and tenants; it never touches a stored secret.
From an OAuth provider’s own endpoints. A generic oauth2 provider populates senders from its
userinfo endpoint (the signed-in subject) and, if the server offers one, from an admin or
directory endpoint named by sendersUrl.
Not every provider signs in per sender. Clerk uses one shared secret key; an oauth2 sender is an
identity the authorization server already knows. The view only asks for a password where the
engine would actually refuse without one — password-grant Keycloak and Auth0, Firebase without a
service account, Supabase — and a sender missing one is flagged rather than silently failing at
send time.
AWS senders are roles
Section titled “AWS senders are roles”For an awsSigV4 provider a sender is not a person: it is an assume-role target, and the
Senders tab is labelled Roles.
The role lives in the sender’s ordinary non-secret vars — roleArn (required), plus optional
sessionName, externalId, durationSeconds and a region override. No new schema field was
added for this, which is the point: “send as the read-only role” is the same dropdown every other
provider has.
Selecting one makes the engine call STS AssumeRole with the provider’s base credentials and sign
with the returned temporary ones, cached under that sender until they expire. A provider with no
roles signs with the base credentials directly.
Choosing one
Section titled “Choosing one”A request’s auth block names the provider and, optionally, the sender:
auth: provider: users-api sender: admin@example.comLeave sender out and the provider’s default is used. The Auth tab has a picker; the Auth
providers view marks one sender as the default with a star.
Tokens are cached per sender, so switching back and forth does not re-authenticate each time.
In a script
Section titled “In a script”The selected sender is passed to an auth script, which is how one script serves every identity:
async function authenticate({ secret, sender, env, fetch }) { const res = await fetch(`${env.baseUrl}/login`, { method: "POST", body: JSON.stringify({ user: sender.id, pass: secret(sender.secretRef), }), }); return { token: (await res.json()).token };}Why it matters
Section titled “Why it matters”Authorization bugs are the ones that reach production, because “it worked when I tried it” usually means “it worked as me”. Senders make the other half cheap: send the same endpoint as an admin, as a viewer, and as somebody from a different tenant, and compare the statuses.
An agent can do that too. list_senders returns the identities of one
provider or of all of them — id, label, tenant, which is default, and whether the engine would
actually be able to use it (with the reason when it could not) — and send_request takes a
sender. So “probe this endpoint as each of these three identities and show me the statuses” is
one instruction.
Names only, as everywhere else: never a token, a password, or even a secret name.
The tinspec CLI takes --sender for the same reason, which is what lets a pipeline perform the
real login rather than replaying a stored token.