signet identity authority API. bridge certificates via OIDC token exchange, GHA automation, and agent registration.
extractable: false and proves possession; only certificates come back. Earlier revisions of this page showed a private_key field — no endpoint has ever returned one.
Bearer <GHA OIDC token> with audience
notme.bot
Authorization header, not
in the body. Each proof is a signature by the corresponding
private key over the binding PRE-IMAGE
mtls_spki ‖ signing_spki ‖ SHA-256(oidc_jwt)
— the raw bytes, never their digest.
GHA_ALLOWED_OWNERS, which has
no default — an authority that has not declared whose
workflows it trusts trusts none. The token is spent on first use
(jti replay protection) and exchanges are rate
limited per repository.
sub, which is also the certificate CN — rather
than the attestation mechanism. Owner and repository remain
readable from sub and from the returned claims.
/cert/gha: an authenticated
browser session plus proof of possession, in exchange for a bridge
cert pair. Accepts any valid session — passkey, invite, or
OIDC — and derives the certificate's identity and auth method
from the session, so a certificate never claims an authenticator
the session did not use.
authorityManage and certMint; a
certificate that silently inherited them would turn a cookie into
a minting credential with none of the properties that made the
cookie acceptable.
A session cookie, plus a DPoP proof header signed by
the client's own P-256 key. Tokens are sender-constrained: a
stolen token is useless without that key.
POST /authorize/code,
POST /authorize/redeem and
POST /authorize/token complete it.
/.well-known/openid-configuration, but signet consumes
OIDC — it does not issue tokens.
/.well-known/openid-configuration — same body,
and ONLY because many client libraries probe exclusively there.
notme is not an OpenID Provider: it issues no
id_token, honours no scope=openid, and
publishes an empty response_types_supported.
id_token_signing_alg_values_supported: ["EdDSA"].
That is a correctness requirement, not a capability claim: a
client whose discovery is silent on algorithms defaults to RS256
alone and rejects every token this issuer signs.
{kty:"OKP", crv:"Ed25519", alg:"EdDSA"}. "EdDSA" is
the JWA algorithm name (RFC 8037 §3.1); "Ed25519" is the curve.
/.well-known/epochs.json) and by short
certificate lifetimes. Do not build a verifier that waits for a
revocation list — none is coming.
Accept: application/json).
/healthz. Answered at
the edge — no auth, no Durable Object, no upstream. Replied
to before host canonicalization, so probes from a bare IP or from
inside a cluster get an answer rather than a redirect.
signet is not an identity provider — it is an identity attester. You own your key. signet signs a short-lived certificate binding your public key to your verified identity.
Two grant types are advertised, and they are the only two implemented:
POST /cert/gha with a GitHub OIDC JWT
(no stored secret)
POST /token with a
DPoP proof (RFC 9449)
Everything else that gets you in is an authentication method,
not a grant, and the two are deliberately not conflated: passkey,
invite, and oidc:github establish a session; a grant
issues a token. An earlier revision of this page advertised
oidc_token_exchange and github_pat as grant
types. Neither was ever implemented — the discovery document now
derives its list from a single constant in the code, so a published
capability claim and the code cannot drift apart again.
No endpoint returns a private key. The caller generates its keypairs locally, ideally non-extractable, and proves possession of them; only certificates come back. That is the property the whole design exists to provide, and it holds on every route above.
All certificates are Ed25519-signed X.509 with custom OID extensions for subject identity and issuance time, matching the Go authority format.