THIS LIBRARY IS DEPRECATED
Projects using this library should consider migrating to the community-maintained fork over at github.com/go-webauthn/webauthn. See the Migration Guide for more information.
The original README continues below.
WebAuthn Library
=============
This library is meant to handle Web Authentication for Go apps that wish to implement a passwordless solution for users. While the specification is currently in Candidate Recommendation, this library conforms as much as possible to
the guidelines and implementation procedures outlined by the document.
Demo at webauthn.io
An implementation of this library can be used at webauthn.io and the code for this website can be found in the Duo Labs repository webauthn-io
.
Simplified demo
A simplified demonstration of this library can be found here. It includes a minimal interface and is great for quickly testing out the code. The associated blog post can be found here.
Quickstart
go get github.com/duo-labs/webauthn
and initialize it in your application with basic configuration values.
Make sure your user
model is able to handle the interface functions laid out in webauthn/user.go
. This means also supporting the storage and retrieval of the credential and authenticator structs in webauthn/credential.go
and webauthn/authenticator.go
, respectively.
Initialize the request handler
import "github.com/duo-labs/webauthn/webauthn"
var (
web *webauthn.WebAuthn
err error
)
func main() {
web, err = webauthn.New(&webauthn.Config{
RPDisplayName: "Duo Labs",
RPID: "duo.com",
RPOrigin: "https://login.duo.com",
RPIcon: "https://duo.com/logo.png",
})
if err != nil {
fmt.Println(err)
}
}
Registering an account
func BeginRegistration(w http.ResponseWriter, r *http.Request) {
user := datastore.GetUser()
options, sessionData, err := web.BeginRegistration(&user)
JSONResponse(w, options, http.StatusOK)
}
func FinishRegistration(w http.ResponseWriter, r *http.Request) {
user := datastore.GetUser()
sessionData := store.Get(r, "registration-session")
parsedResponse, err := protocol.ParseCredentialCreationResponseBody(r.Body)
credential, err := web.CreateCredential(&user, sessionData, parsedResponse)
JSONResponse(w, "Registration Success", http.StatusOK)
}
Logging into an account
func BeginLogin(w http.ResponseWriter, r *http.Request) {
user := datastore.GetUser()
options, sessionData, err := webauthn.BeginLogin(&user)
JSONResponse(w, options, http.StatusOK)
}
func FinishLogin(w http.ResponseWriter, r *http.Request) {
user := datastore.GetUser()
sessionData := store.Get(r, "login-session")
parsedResponse, err := protocol.ParseCredentialRequestResponseBody(r.Body)
credential, err := webauthn.ValidateLogin(&user, sessionData, parsedResponse)
JSONResponse(w, "Login Success", http.StatusOK)
}
Modifying Credential Options
You can modify the default credential creation options for registration and login by providing optional structs to the BeginRegistration
and BeginLogin
functions.
Registration modifiers
You can modify the registration options in the following ways:
import "github.com/duo-labs/webauthn/protocol"
import "github.com/duo-labs/webauthn/webauthn"
var webAuthnHandler webauthn.WebAuthn
func beginRegistration() {
authSelect := protocol.AuthenticatorSelection{
AuthenticatorAttachment: protocol.AuthenticatorAttachment("platform"),
RequireResidentKey: protocol.ResidentKeyUnrequired(),
UserVerification: protocol.VerificationRequired
}
conveyancePref := protocol.ConveyancePreference(protocol.PreferNoAttestation)
user := datastore.GetUser()
opts, sessionData, err webAuthnHandler.BeginRegistration(&user, webauthn.WithAuthenticatorSelection(authSelect), webauthn.WithConveyancePreference(conveyancePref))
}
Login modifiers
You can modify the login options to allow only certain credentials:
import "github.com/duo-labs/webauthn/protocol"
import "github.com/duo-labs/webauthn/webauthn"
var webAuthnHandler webauthn.WebAuthn
func beginLogin() {
allowList := make([]protocol.CredentialDescriptor, 1)
allowList[0] = protocol.CredentialDescriptor{
CredentialID: credentialToAllowID,
Type: protocol.CredentialType("public-key"),
}
user := datastore.GetUser()
opts, sessionData, err := webAuthnHandler.BeginLogin(&user, webauthn.wat.WithAllowedCredentials(allowList))
}
Acknowledgements
I could not have made this library without the work of Jordan Wright and the designs done for our demo site by Emily Rosen. When I began refactoring this library in December 2018, Koen Vlaswinkel's Golang WebAuthn library really helped set me in the right direction. A huge thanks to Alex Seigler for his continuing work on this WebAuthn library and many others. Thanks to everyone who submitted issues and pull requests to help make this library what it is today!