{"id":19619693,"url":"https://github.com/fxamacker/webauthn-demo","last_synced_at":"2025-04-28T03:31:30.450Z","repository":{"id":57543174,"uuid":"202466769","full_name":"fxamacker/webauthn-demo","owner":"fxamacker","description":"WebAuthn server demo for registration and authentication (Go/Golang)","archived":false,"fork":false,"pushed_at":"2020-01-20T15:15:02.000Z","size":143,"stargazers_count":12,"open_issues_count":2,"forks_count":4,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-05T05:41:26.428Z","etag":null,"topics":["authentication","fido2","passwordless","security","web-application","webauthn","webauthn-demo","yubikey"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/fxamacker.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-08-15T03:21:34.000Z","updated_at":"2024-03-20T21:31:29.000Z","dependencies_parsed_at":"2022-09-06T03:41:29.514Z","dependency_job_id":null,"html_url":"https://github.com/fxamacker/webauthn-demo","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fxamacker%2Fwebauthn-demo","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fxamacker%2Fwebauthn-demo/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fxamacker%2Fwebauthn-demo/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fxamacker%2Fwebauthn-demo/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fxamacker","download_url":"https://codeload.github.com/fxamacker/webauthn-demo/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251245709,"owners_count":21558734,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["authentication","fido2","passwordless","security","web-application","webauthn","webauthn-demo","yubikey"],"created_at":"2024-11-11T11:14:41.455Z","updated_at":"2025-04-28T03:31:30.169Z","avatar_url":"https://github.com/fxamacker.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Build Status](https://travis-ci.com/fxamacker/webauthn-demo.svg?branch=master)](https://travis-ci.com/fxamacker/webauthn-demo)\n[![Go Report Card](https://goreportcard.com/badge/github.com/fxamacker/webauthn-demo)](https://goreportcard.com/report/github.com/fxamacker/webauthn-demo)\n[![GitHub](https://img.shields.io/github/license/fxamacker/webauthn-demo)](https://github.com/fxamacker/webauthn-demo/blob/master/LICENSE)\n\n# WebAuthn Server Demo (Go/Golang)\n\nThis web app is a demo for my [WebAuthn server library](https://www.github.com/fxamacker/webauthn) (fxamacker/webauthn).  It supports [WebAuthn](https://w3c.github.io/webauthn/) registration and authentication.  It implements [proposed REST API](https://fidoalliance.org/specs/fido-v2.0-rd-20180702/fido-server-v2.0-rd-20180702.html#transport-binding-profile) for FIDO2 servers.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://user-images.githubusercontent.com/57072051/68431219-4e066780-0177-11ea-8a3f-5a137cc76cf1.png\" alt=\"Picture of FIDO U2F key\"\u003e\n\u003c/p\u003e\n\n## What's WebAuthn?\nWebAuthn (Web Authentication) is a [W3C web standard](https://www.w3.org/TR/webauthn/) for authenticating users to web-based apps and services.  It's a core component of [FIDO2](https://en.wikipedia.org/wiki/FIDO2_Project), the successor of FIDO U2F legacy protocol.\n\n## Demo WebAuthn Server Components\n\n* [fxamacker/webauthn](https://www.github.com/fxamacker/webauthn) to parse and validate registration and authentication requests.\n* Bootstrap and jQuery for web interface.\n* gorilla/mux for routing and gorilla/sessions for session management.\n* Redis for session storage. \n* PostgreSQL for data persistence.  \n\n## Current Status\n\nThis demo is not for production use because it's designed to be a demo.\n\n## System Requirements\n\n* Go 1.12 (or newer)\n* Tested on x86_64 but it should work on other little-endian systems supported by Go.\n\n## Installation \n\n```\ngo get github.com/fxamacker/webauthn-demo\n```\n\n## Running WebAuthn Demo Using Docker\n\n```\n$ CERTS_DIR=[folder containing cert.pem and key.pem] docker-compose up\n```\n\nWebAuthn demo runs at https://localhost:8443 on your Docker host.\n\n## Customizing WebAuthn Demo Using Docker \n\n* Edit [config.json](config.json) to change WebAuthn server settings as needed.\n* Edit [.env](.env) as needed:\n  * CERTS_DIR: folder containing cert.pem and key.pem.\n  * DB_NAME: database name (default: webauthn).\n  * DB_PASSWORD: database password (default: dockerpwd).\n  * DB_USER: database user (default: docker).\n  * DB_DATA_DIR: database storage folder.\n  * CACHE_DATA_DIR: cache storage folder.\n  * SESSION_KEY: base64 encoded session encryption key.\n* Run WebAuthn demo: \n\n```\n$ docker-compose up\n```\n\nWebAuthn demo runs at https://localhost:8443 on your Docker host.\n\n## Registration\n\n[Registration](https://fidoalliance.org/specs/fido-v2.0-rd-20180702/fido-server-v2.0-rd-20180702.html#registration-overview) process consists of two steps: create credential creation options and register credentials.  See [signup.html](static/signup.html), [webauthn.register.js](static/js/webauthn.register.js), and [registration_handlers.go](registration_handlers.go).\n\n**Create credential creation options:**\n\nServer handles `/attestation/options` request by returning credential creation options (PublicKeyCredentialCreationOptions) to client.  Client then uses those options with `navigator.credentials.create()` to create new credentials.  \n\n```\n// Simplified `/attestation/options` handler from registration_handlers.go\nfunc (s *server) handleAttestationOptions(w http.ResponseWriter, r *http.Request) {\n    // Get user from datastore by username.\n    u, _ := s.dataStore.getUser(r.Context(), optionsRequest.Username)\n    \n    // Create PublicKeyCredentialCreationOptions using webauthn library.\n    creationOptions, _ := webauthn.NewAttestationOptions(s.webAuthnConfig, \u0026webauthn.User{ID: u.UserID, Name: u.UserName, DisplayName: u.DisplayName, CredentialIDs: u.CredentialIDs})\n\n    // Save creationOptions and user info in session to verify new credential later.\n    session.Values[WebAuthnCreationOptions] = creationOptions\n    session.Values[UserSession] = \u0026userSession{User: u}\n\n    // Write creationOptions to response.\n}\n```\n\n**Register credentials:**\n\nServer verifies and registers new credentials received via `/attestation/result`.\n\n```\n// Simplified `/attestation/result` handler from registration_handlers.go\nfunc (s *server) handleAttestationResult(w http.ResponseWriter, r *http.Request) {\n    // Get saved creationOptions and user info from session.\n\n    // Parse and verify credential in request body.\n    credentialAttestation, _ := webauthn.ParseAttestation(r.Body)\n    expected := \u0026webauthn.AttestationExpectedData{\n\tOrigin:           s.rpOrigin,\n\tRPID:             savedCreationOptions.RP.ID,\n\tCredentialAlgs:   credentialAlgs,\n\tChallenge:        base64.RawURLEncoding.EncodeToString(savedCreationOptions.Challenge),\n\tUserVerification: savedCreationOptions.AuthenticatorSelection.UserVerification,\n    }    \n    _, _, err = webauthn.VerifyAttestation(credentialAttestation, expected)\n\n   // Save user credential in datastore.\n   c := \u0026credential{\n\tCredentialID: credentialAttestation.RawID,\n\tUserID:       uSession.User.UserID,\n\tCounter:      credentialAttestation.AuthnData.Counter,\n\tCoseKey:      credentialAttestation.AuthnData.Credential.Raw,\n   }    \n   err = s.dataStore.addUserCredential(r.Context(), uSession.User, c)\n\n   // Write \"ok\" response. \n}\n```\n\n## Authentication\n\n[Authentication](https://fidoalliance.org/specs/fido-v2.0-rd-20180702/fido-server-v2.0-rd-20180702.html#authentication-overview) process requires two steps: create credential request options and verify credentials.  See [signin.html](static/signin.html), [webauthn.authn.js](static/js/webauthn.authn.js), and [authentication_handlers.go](authentication_handlers.go).\n\n**Create credential request options:**\n\nServer handles `/assertion/options` request by returning credential request options (PublicKeyCredentialRequestOptions) to client.  Client then uses those options with `navigator.credentials.get()` to get existing credentials.  \n\n```\n// Simplified `/assertion/options` handler from authentication_handlers.go\nfunc (s *server) handleAssertionOptions(w http.ResponseWriter, r *http.Request) {\n    // Get user from datastore by username.\n    u, _ := s.dataStore.getUser(r.Context(), optionsRequest.Username)\n    \n    // Create PublicKeyCredentialRequestOptions using webauthn library.\n    requestOptions, _ := webauthn.NewAssertionOptions(s.webAuthnConfig, \u0026webauthn.User{ID: u.UserID, Name: u.UserName, DisplayName: u.DisplayName, CredentialIDs: u.CredentialIDs})\n\n    // Save requestOptions and user info in session to verify credential later.\n    session.Values[WebAuthnRequestOptions] = requestOptions\n    session.Values[UserSession] = \u0026userSession{User: u}\n\n    // Write requestOptions to response.\n}\n```\n\n**Verify credentials:**\n\nServer verifies credentials received via `/asssertion/result`.\n\n```\n// Simplified `/assertion/result` handler from authentication_handlers.go\nfunc (s *server) handleAssertionResult(w http.ResponseWriter, r *http.Request) {\n    // Get saved requestOptions and user info.\n\n    // Parse credential in request body.\n    credentialAssertion, _ := webauthn.ParseAssertion(r.Body)\n\n    // Get credential from datastore by received credential ID.\n    c, _ := s.dataStore.getCredential(r.Context(), uSession.User.UserID, credentialAssertion.RawID)\n\n    // Verify credential.\n    expected := \u0026webauthn.AssertionExpectedData{\n\tOrigin:            s.rpOrigin,\n\tRPID:              savedRequestOptions.RPID,\n\tChallenge:         base64.RawURLEncoding.EncodeToString(savedRequestOptions.Challenge),\n\tUserVerification:  savedRequestOptions.UserVerification,\n\tUserID:            uSession.User.UserID,\n\tUserCredentialIDs: userCredentialIDs,\n\tPrevCounter:       c.Counter,\n\tCredential:        credKey,\n    }\n    err = webauthn.VerifyAssertion(credentialAssertion, expected)\n\n    // Update authenticator counter in datastore.\n    c.Counter = credentialAssertion.AuthnData.Counter\n    err = s.dataStore.updateCredential(r.Context(), c)\n\n    // Write \"ok\" response. \n}\n```\n\n## Security Policy\n\nSecurity fixes are provided for the latest released version.\n\nTo report security vulnerabilities, please email faye.github@gmail.com and allow time for the problem to be resolved before reporting it to the public.\n\n## License \n\nCopyright (c) 2019-present [Faye Amacker](https://github.com/fxamacker)\n\nfxamacker/webauthn-demo is licensed under the Apache License, Version 2.0. See [LICENSE](LICENSE) for the full license text.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffxamacker%2Fwebauthn-demo","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffxamacker%2Fwebauthn-demo","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffxamacker%2Fwebauthn-demo/lists"}