Go library for proving that an application subject controls a DN42 ASN.
The library is inspired by the login flows in
github.com/AS214933/dn42-bot, but it
is a standalone Go package rather than a Telegram bot component.
- Email OTP login against email addresses discovered from DN42 registry contact objects.
- GPG clearsigned challenge verification against
pgpkey-*andpgp-fingerprint *maintainer auth entries. - SSH signature verification for OpenSSH
ssh-keygen -Y signsignatures againstssh-*maintainer auth entries. - Optional OIDC/OAuth helper for providers that expose a DN42 ASN claim such as
dn42.asn. - Pluggable registry, mailer, challenge store, clock, randomness, and GPG key providers.
auth: ASN parsing, challenge orchestration, email OTP, GPG/SSH signatures, and OIDC/OAuth binding.registry: registry object parsing plus file, git-backed, whois, and composite data sources.
Requires Go 1.25 or newer.
go get github.com/AS214933/go-dn42-authimport (
"github.com/AS214933/go-dn42-auth/auth"
"github.com/AS214933/go-dn42-auth/registry"
)Use the default git-backed DN42 registry source. It clones
https://git.origami.pub/Bingxin/dn42-registry on first use:
reg := registry.NewGit("/var/cache/dn42-registry")
verifier := auth.New(reg)Override the registry Git URL when you need a mirror or private fork:
reg := registry.NewGit(
"/var/cache/dn42-registry",
registry.WithURL("https://git.example.net/dn42-registry"),
)
verifier := auth.New(reg)If you manage the clone yourself, use a local DN42 registry directory:
reg := registry.NewFile("/srv/dn42-registry")
verifier := auth.New(reg)NewGit reuses an existing clone by default. Add
registry.WithAutoPull(true) if lookups should pull updates first.
Or combine a local registry with a whois fallback:
reg := registry.Composite{
registry.NewFile("/srv/dn42-registry"),
®istry.Whois{Address: "whois.dn42"},
}
verifier := auth.New(reg)verifier := auth.New(reg, auth.WithMailer(auth.MailerFunc(
func(ctx context.Context, msg auth.OTPMessage) error {
// Send msg.Code to msg.Email with your SMTP or mail provider.
return nil
},
)))
subject := auth.Subject{ID: "user:123"}
challenge, err := verifier.BeginEmailOTP(ctx, subject, auth.ASN(4242421234), "noc@example.net")
if err != nil {
// The email must be listed on the ASN's registry contacts.
}
proof, err := verifier.VerifyEmailOTP(ctx, challenge.ID, userSuppliedCode)challenge, err := verifier.BeginSignature(ctx, subject, auth.ASN(4242421234), auth.SignatureAny)
if err != nil {
// The ASN must have GPG or SSH auth entries in its mntner object.
}
fmt.Println(challenge.Text)For SSH:
printf '%s' "$CHALLENGE_TEXT" > challenge.txt
ssh-keygen -Y sign -f ~/.ssh/id_ed25519 -n file challenge.txtFor GPG:
printf '%s' "$CHALLENGE_TEXT" | gpg --clearsignThen verify the returned signed text:
proof, err := verifier.VerifySignature(ctx, challenge.ID, []byte(signedText))GPG public keys are loaded from DN42 key-cert objects first and then from
HTTPS keyservers by default. Override this with auth.WithGPGKeyProvider when your
application wants to pin keys or avoid network lookups.
For providers that expose a DN42 ASN claim:
oidcVerifier, err := auth.NewOIDCVerifier(ctx, auth.OIDCConfig{
IssuerURL: "https://auth.example.net",
ClientID: "client-id",
ClientSecret: "client-secret",
RedirectURL: "https://app.example.net/callback",
Scopes: []string{"dn42"},
ASNClaim: "dn42.asn",
ASNClaimSource: auth.OIDCClaimAuto,
})
url := oidcVerifier.AuthCodeURL(state, oauth2.SetAuthURLParam("nonce", nonce))After the callback:
result, err := oidcVerifier.ExchangeAndVerify(ctx, code, nonce)
proof, err := auth.VerifyOAuthASN(subject, auth.ASN(4242421234), result, nil)Your application remains responsible for state and nonce storage.
- Store challenge IDs server-side and expire them quickly. The default in-memory store uses a 10 minute challenge TTL.
- Custom
auth.ChallengeStoreimplementations must makeUpdateatomic per challenge ID so OTP attempt limits and one-time challenge consumption remain race-safe. - Bind
Subject.IDto your own account/session identifier, not to display text. - Run a fresh DN42 registry clone or trusted whois source.
- Prefer HTTPS key lookup or pinned GPG keys when registry
key-certobjects are absent. - OIDC/OAuth verification is only as strong as the provider and claim mapping you configure.
go test ./...