webauthn

package module
v0.4.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 4, 2026 License: MIT Imports: 15 Imported by: 0

README

WebAuthn2Go - Go WebAuthn Server Library

docs/hero.png

Go Reference

A Go library designed to simplify the server-side implementation of the WebAuthn (FIDO2) protocol for passwordless authentication.

Features

  • WebAuthn Server Logic: Handles core server-side registration and authentication ceremonies.
  • Attestation Support:
    • Accepts none, indirect, and packed attestation formats.
      • Currently, skips cryptographic verification of attestation statements (AttStmt), focusing on extracting authenticator data (AuthData) including AAGUID and Public Key.
  • Assertion Verification: Validates login assertions including challenge, origin, RP ID, user presence/verification flags, and signature.
  • Sign Count Protection: Checks for increasing sign counts to help prevent replay attacks (requires secure storage by the caller).
  • AAGUID Lookup: Provides a utility to look up authenticator names based on AAGUID.
  • Extensions Support: Basic support for WebAuthn extensions.
  • Configuration: Simple configuration for Relying Party details.

Why this library?

This library is designed to be easy to use and integrate into existing Go applications. You don't need to especially implement custom interfaces or convert your Fiber's fasthttp.Request into http.Request, like in https://github.com/go-webauthn/webauthn. There are no other alternatives, except the https://github.com/egregors/passkey, which is a wrapper around the first one, which additionally can set cookies for you.

If you want more flexibility or control, and you don't need fancy features - this is the library for You.

Why NOT this library?

This library is not intended to be a full-fledged WebAuthn implementation. It does not handle attestation verification, for example. This library is also in early development, so may be not suitable for production use yet.

The library is also not popular. It's possible that this repo has more or less zero stars and has never been reviewed or used by the third party. So, if you are looking for a battle-tested library, this is not the one.

One more thing - the code is written with the partial help of AI. Although the author tried his best to understand WebAuthn specification and read various sources, the code may be far from perfect or even insecure. Every line of code has been read and verified by myself. It wasn't just do webauthn lib wololo in ChatGPT. But still, please use it at your own risk.

Used sources:

[!WARNING] This library supports only Go 1.24 and above.

Example

There is a simple example in the example folder. It uses the github.com/gofiber/fiber/v2 web framework, but you can use whatever you want.

Installation

go get github.com/MrBoombastic/WebAuthn2Go

Configuration

Before using the library, you need to configure your Relying Party (RP) details and other minor settings.

w, err := webauthn.New(&webauthn.Config{
    RPID:             "localhost",                       // Domain name only - must match the domain in your URL
    RPDisplayName:    "WebAuthn2Go Example",             // Display name
    RPOrigins:        []string{"https://yourdomain.com", "https://auth.yourdomain.com"}, // Allowed origins - with protocol and port
    Timeout:          300_000,                           // Milliseconds, 5 minutes
    UserVerification: webauthn.UVPreferred,              // User verification requirement
    Attestation:      webauthn.AttestationIndirect,      // Attestation preference, Indirect gives us AAGUID
    Debug:            true,                              // Enable debug logging
})

w, err := webauthn.New(rpConfig)
if err != nil {
  // Handle configuration error (e.g., missing RPID/Origins)
  log.Fatalf("Failed to initialize WebAuthn: %v", err)
}

[!IMPORTANT]

  • RPID must be the effective domain of your web application. Browsers enforce this strictly.
  • RPOrigins must include all origins (scheme + host + port if non-default) from which WebAuthn requests will originate. Mismatched origins will cause browser errors.

Usage Overview

The library provides functions to handle the two main WebAuthn ceremonies: Registration (Create) and Authentication ( Get).

Please refer to the example folder for a complete example (with SQLite3 support) of how to use the library. The key methods are BeginRegistration, FinishRegistration, BeginLogin, and FinishLogin. You will have to provide required data and save returned data manually by yourself.

Key Caller Responsibilities:
  • User Management: Maintain your user database.
  • Credential Storage: Securely store the CredentialID, PublicKey, AAGUID, and SignCount associated with each user after successful registration.
  • Challenge Storage: Securely store the challenge used for registration and authentication.

AAGUID Lookup subpackage

The library includes a subpackage for AAGUID lookup. You are welcome to use it in your own projects. Go to example_aaguid for more.

package main

import (
	"fmt"
	"github.com/MrBoombastic/WebAuthn2Go/aaguid"
	"github.com/google/uuid"
)

func main() {
	fmt.Println(aaguid.LookupAuthenticatorUUID(uuid.MustParse("ed042a3a-4b22-4455-bb69-a267b652ae7e")))
	// Security Key NFC - Enterprise Edition (USB-A, USB-C) (Black) FW 5.7
}

Dependencies

  • github.com/google/uuid additional library used for AAGUID subpackage
  • github.com/go-webauthn/webauthn/protocol/webauthncbor for CBOR decoding.
  • github.com/go-webauthn/webauthn/protocol/webauthncose for parsing COSE public keys.

That may sound weird, that alternative to go-webauthn/webauthn uses that library, but actually there is no other choice if you want to support more than just ES256 algorithm. I'm also assuming that outsourcing "the hard stuff" to more popular libraries is a safer choice.

Security Considerations

  • Challenge Management: Ensure challenges are unique per operation, securely stored server-side (e.g., in authenticated sessions), and used only once.
  • Credential Storage: Store public keys and especially sign counts securely. Compromise of the sign count storage negates replay protection.
  • Origin/RP ID Configuration: Incorrect RPID or RPOrigins configuration will break functionality and is a security boundary.
  • Attestation Verification: This library currently does not perform cryptographic verification of attestation statements for indirect or packed formats. It only parses the authenticator data. If you require stricter verification of authenticator provenance, you would need to implement the specific verification logic for those formats.

Contributing

Contributions are welcome! Please feel free to submit pull requests or open issues.

License

This project is licensed under the MIT License - see the LICENSE file for details.

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrNilConfig                                   = errors.New("config cannot be nil")
	ErrNilInstance                                 = errors.New("webauthn instance is not initialized")
	ErrAttestationNotSupported                     = errors.New("unsupported attestation preference requested")
	ErrInvalidUserVerification                     = errors.New("invalid user verification preference in config")
	ErrInvalidRPOrigins                            = errors.New("invalid RP origins")
	ErrInvalidRPOrigin                             = errors.New("invalid RP origin")
	ErrEmptyRPID                                   = errors.New("RP ID cannot be empty")
	ErrEmptyRPDisplayName                          = errors.New("RP display name cannot be empty")
	ErrInvalidTimeout                              = errors.New("timeout must be greater than 0")
	ErrParsingOrigin                               = errors.New("error parsing origin")
	ErrOriginNotAllowed                            = errors.New("origin not allowed")
	ErrFailedUnmarshalClientData                   = errors.New("failed to unmarshal client data")
	ErrTypeNotWebauthnGet                          = errors.New("client data type is not webauthn.get")
	ErrTypeNotWebauthnCreate                       = errors.New("client data type is not webauthn.create")
	ErrFailedDecodeAuthData                        = errors.New("failed to decode authenticator data")
	ErrFailedParseAuthData                         = errors.New("failed to parse authenticator data")
	ErrFailedParseClientData                       = errors.New("failed to parse client data")
	ErrFailedDecodeClientData                      = errors.New("failed to decode client data")
	ErrRPIDHashMismatch                            = errors.New("RP ID hash mismatch")
	ErrUserPresentFlagNotSet                       = errors.New("flag User Present not set")
	ErrUserVerifiedFlagNotSet                      = errors.New("flag User Verified not set")
	ErrFailedDecodeSignature                       = errors.New("failed to decode signature")
	ErrSignatureVerification                       = errors.New("signature verification error")
	ErrInvalidSignature                            = errors.New("invalid signature")
	ErrSignatureCountMismatch                      = errors.New("signature count mismatch")
	ErrGeneratingChallenge                         = errors.New("error generating challenge")
	ErrFailedDecodeAttestationObject               = errors.New("failed to decode attestation object")
	ErrUnsupportedAttestationFormat                = errors.New("unsupported attestation format received")
	ErrMissingPublicKey                            = errors.New("missing public key")
	ErrInvalidPublicKey                            = errors.New("invalid public key format")
	ErrMissingCredentialID                         = errors.New("missing credential ID")
	ErrAuthDataTooShort                            = errors.New("auth data too short, expected at least 37 bytes")
	ErrAuthDataTooShortAttested                    = errors.New("auth data too short for attested credential data header")
	ErrAAGUIDToUUID                                = errors.New("error converting AAGUID to UUID")
	ErrAuthDataTooShortCredentialID                = errors.New("auth data too short for credential ID")
	ErrParsingCOSEKey                              = errors.New("error parsing COSE key data")
	ErrATFlagButNoData                             = errors.New("AT flag set, but no data remains for public key")
	ErrEDFlagButNoData                             = errors.New("ED flag set, but no data remains after parsing previous parts")
	ErrFailedDecodeExtensionData                   = errors.New("failed to decode extension data")
	ErrFailedUnmarshalPublicKeyCredential          = errors.New("failed to unmarshal public key credential")
	ErrFailedUnmarshalPublicKeyCredentialAssertion = errors.New("failed to unmarshal public key credential assertion")
)

Functions

This section is empty.

Types

type AttestationPreference

type AttestationPreference string

AttestationPreference defines the level of attestation requested.

const (
	AttestationNone     AttestationPreference = "none"
	AttestationIndirect AttestationPreference = "indirect"
	AttestationPacked   AttestationPreference = "packed"
)

func (AttestationPreference) IsValid

func (ap AttestationPreference) IsValid() bool

IsValid checks if the AttestationPreference is one of the defined constants.

type BeginRegistrationOptions

type BeginRegistrationOptions struct {
	Challenge        string                      `json:"challenge"`
	RP               RelyingPartyEntity          `json:"rp"`
	User             UserEntity                  `json:"user"`
	PubKeyCredParams []CredentialParameter       `json:"pubKeyCredParams"`
	Timeout          uint32                      `json:"timeout"`
	Attestation      AttestationPreference       `json:"attestation"`
	UserVerification UserVerificationRequirement `json:"userVerification,omitempty"`
}

BeginRegistrationOptions holds options for navigator.credentials.create()

type ClientData

type ClientData struct {
	Type      string `json:"type"`
	Challenge string `json:"challenge"`
	RPOrigin  string `json:"origin"`
}

ClientData represents the common structure of client data in both registration and login

func (*ClientData) ParseWithB64

func (c *ClientData) ParseWithB64(jsonData string) (b64 []byte, err error)

ParseWithB64 parses client data JSON and also returns the base64 encoded version

type Config

type Config struct {
	RPID             string                      // Relying Party ID (e.g., "example.com")
	RPDisplayName    string                      // Relying Party display name (e.g., "Example Corp")
	RPOrigins        []string                    // Allowed origins for RP assertions (e.g., ["https://example.com", "https://login.example.com:2137"])
	Timeout          uint32                      // Default timeout for operations (milliseconds)
	UserVerification UserVerificationRequirement // Default User Verification Requirement
	Attestation      AttestationPreference       // Default Attestation Preference
	Debug            bool                        // Enable debug logging
}

Config holds the configuration for the WebAuthn library. Ensure RPOrigin(s) are set correctly for security checks.

type CredentialParameter

type CredentialParameter struct {
	Type string `json:"type"`
	Alg  int64  `json:"alg"`
}

CredentialParameter defines a credential parameter

type LoginData

type LoginData struct {
	ClientDataJSON  string `json:"clientDataJSON"`
	AuthData        string `json:"authData"`
	Signature       string `json:"signature"`
	StoredSignCount uint32 `json:"storedSignCount"`
	PublicKey       []byte `json:"publicKey"`
}

type LoginResult

type LoginResult struct {
	NewSignCount uint32 `json:"newSignCount"`
	UserVerified bool   `json:"userVerified"`
}

LoginResult holds the successful result of an authentication (login) ceremony.

type ParsedAuthData

type ParsedAuthData struct {
	RPIDHash              []byte
	Flags                 byte
	SignCount             uint32
	AAGUID                uuid.UUID // Present if AT flag is set
	CredentialID          []byte    // Present if AT flag is set
	CredentialPubKeyBytes []byte
	Extensions            map[string]any // Present if ED flag is set
}

ParsedAuthData holds the structured information from the authenticator data.

type PublicKeyCredential

type PublicKeyCredential struct {
	ID                string `json:"id"`
	AttestationObject string `json:"attestationObject"`
	ClientDataJSON    string `json:"clientDataJSON"`
	// contains filtered or unexported fields
}

func (*PublicKeyCredential) ClientData

func (pkc *PublicKeyCredential) ClientData() (c *ClientData)

func (*PublicKeyCredential) Parse

func (pkc *PublicKeyCredential) Parse(data []byte) (err error)

type PublicKeyCredentialAssertion

type PublicKeyCredentialAssertion struct {
	// Matches PublicKeyCredential structure from client Assertion
	ID                string `json:"id"`
	Type              string `json:"type"`
	AuthenticatorData string `json:"authenticatorData"`
	ClientDataJSON    string `json:"clientDataJSON"`

	Signature  string `json:"signature"`
	UserHandle string `json:"userHandle"`
	// contains filtered or unexported fields
}

func (*PublicKeyCredentialAssertion) GetChallenge

func (p *PublicKeyCredentialAssertion) GetChallenge() string

func (*PublicKeyCredentialAssertion) Parse

func (p *PublicKeyCredentialAssertion) Parse(data []byte) (err error)

type PublicKeyCredentialDescriptor

type PublicKeyCredentialDescriptor struct {
	Type string `json:"type"`
	ID   string `json:"id"`
}

PublicKeyCredentialDescriptor defines allowed credentials for login

type PublicKeyCredentialRequestOptions

type PublicKeyCredentialRequestOptions struct {
	Challenge        string                          `json:"challenge"`
	Timeout          uint32                          `json:"timeout"`
	RPID             string                          `json:"rpId"`
	AllowCredentials []PublicKeyCredentialDescriptor `json:"allowCredentials"`
	UserVerification UserVerificationRequirement     `json:"userVerification"`
}

PublicKeyCredentialRequestOptions holds options for navigator.credentials.get()

type RegistrationData

type RegistrationData struct {
	ClientDataJSON    string `json:"clientDataJSON"`
	AttestationObject string
}

RegistrationData holds the inputs for completing a registration ceremony.

type RegistrationResult

type RegistrationResult struct {
	CredentialID      string
	PublicKey         []byte
	AAGUID            string
	AuthenticatorName string
	SignCount         uint32
	Extensions        map[string]any // optional
}

RegistrationResult holds the successful result of a registration ceremony.

type RelyingPartyEntity

type RelyingPartyEntity struct {
	ID   string `json:"id"`
	Name string `json:"name"`
}

type UserEntity

type UserEntity struct {
	ID          []byte `json:"id"`
	Name        string `json:"name"`
	DisplayName string `json:"displayName"`
}

UserEntity represents the user entity

type UserVerificationRequirement

type UserVerificationRequirement string

UserVerificationRequirement defines the requirement level for user verification.

const (
	UVRequired    UserVerificationRequirement = "required"
	UVPreferred   UserVerificationRequirement = "preferred"
	UVDiscouraged UserVerificationRequirement = "discouraged"
)

func (UserVerificationRequirement) IsValid

func (uv UserVerificationRequirement) IsValid() bool

IsValid checks if the UserVerificationRequirement is one of the defined constants.

type ValidationOutput

type ValidationOutput struct {
	NewSignCount uint32 `json:"newSignCount"`
	UserVerified bool   `json:"userVerified"`
}

ValidationOutput holds results from the internal validateAssertion method.

type WebAuthn

type WebAuthn struct {
	Config *Config
	// contains filtered or unexported fields
}

WebAuthn struct holds the configuration and manages WebAuthn operations.

func New

func New(config *Config) (*WebAuthn, error)

New creates a new WebAuthn instance with the provided configuration. It preparses and validates the RPOrigins.

func (*WebAuthn) BeginLogin

func (w *WebAuthn) BeginLogin(allowedCredentialIDs []string) (*PublicKeyCredentialRequestOptions, error)

BeginLogin generates options for the login process using a pre-generated challenge. Returns options (with base64url challenge) or an error.

func (*WebAuthn) BeginRegistration

func (w *WebAuthn) BeginRegistration(user UserEntity) (navigator *BeginRegistrationOptions, err error)

BeginRegistration starts the WebAuthn registration process It generates a challenge (as bytes) and returns options including the challenge encoded as a base64url string. Attestation preference is passed as a parameter. User verification preference is taken from the WebAuthn configuration. FLOW: 1. pass data

func (*WebAuthn) FinishLogin

func (w *WebAuthn) FinishLogin(data *LoginData) (*LoginResult, error)

FinishLogin completes the WebAuthn login process.

func (*WebAuthn) FinishRegistration

func (w *WebAuthn) FinishRegistration(data RegistrationData) (*RegistrationResult, error)

FinishRegistration completes the WebAuthn registration process FLOW 1: pass data

func (*WebAuthn) ParseAuthenticatorData

func (w *WebAuthn) ParseAuthenticatorData(authDataBytes []byte) (*ParsedAuthData, error)

ParseAuthenticatorData returns the parsed data structure or an error

func (*WebAuthn) ValidateLoginData

func (w *WebAuthn) ValidateLoginData(c *LoginData) (out ValidationOutput, err error)

ValidateLoginData performs the core cryptographic verification of an assertion.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL