{"id":20339135,"url":"https://github.com/nealfennimore/passkeys","last_synced_at":"2025-09-24T18:31:28.224Z","repository":{"id":141678573,"uuid":"589386288","full_name":"nealfennimore/passkeys","owner":"nealfennimore","description":"Passkeys demo using Cloudflare Workers, KV, and D1","archived":false,"fork":false,"pushed_at":"2024-07-16T15:28:22.000Z","size":530,"stargazers_count":77,"open_issues_count":0,"forks_count":5,"subscribers_count":5,"default_branch":"main","last_synced_at":"2025-01-08T16:17:24.396Z","etag":null,"topics":["passkey","passkeys","passkeys-demo","typescript","webauthn","webauthn-demo"],"latest_commit_sha":null,"homepage":"https://passkeys.neal.codes","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nealfennimore.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-01-16T01:15:00.000Z","updated_at":"2025-01-02T10:08:29.000Z","dependencies_parsed_at":null,"dependency_job_id":"f172bd0e-fc6e-47e5-95d0-80a6e0263337","html_url":"https://github.com/nealfennimore/passkeys","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/nealfennimore%2Fpasskeys","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nealfennimore%2Fpasskeys/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nealfennimore%2Fpasskeys/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nealfennimore%2Fpasskeys/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nealfennimore","download_url":"https://codeload.github.com/nealfennimore/passkeys/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":234109814,"owners_count":18781541,"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":["passkey","passkeys","passkeys-demo","typescript","webauthn","webauthn-demo"],"created_at":"2024-11-14T21:15:30.620Z","updated_at":"2025-09-24T18:31:22.700Z","avatar_url":"https://github.com/nealfennimore.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Passkeys Demo\n\n\u003e [!WARNING]\n\u003e **This passkeys demo is not secure.**\n\u003e It still needs input validation on everything, however it is at least a somewhat reasonable way of architecting and storing passkeys.\n\n## Architecture\n\n-   Cloudflare workers for server endpoints\n-   Cloudflare KV for temporary cache\n-   Cloudflare D1 for storing public keys and user information\n-   Github pages for the client code\n\n### Database\n\nSee [database schema](https://github.com/nealfennimore/passkeys/blob/main/src/server/db/schema/schema.sql).\n\n```mermaid\nerDiagram\n\tusers {\n        text id PK \"Stored as UUID\"\n\t\ttimestamp created_at\n    }\n    public_keys {\n        text kid PK \"Stored as UUID\"\n        blob pubkey\n        blob attestation_data\n\t\tint cose_alg\n\t\tblob sign_counter\n\t\ttext user_id FK \"Stored as UUID\"\n\t\ttimestamp created_at\n\t\ttimestamp updated_at\n    }\n\n\tusers ||--|{ public_keys: contains\n```\n\n### Cache\n\nAll challenges expire in 5 minutes. All sessions expire in 24 hours.\n\n```mermaid\nerDiagram\n\tchallenges {\n        string session_type \"Key of 'session_uuid:webauthn_type'\"\n\t\tstring challenge \"Random challenge generated for session\"\n    }\n\n\tsessions {\n\t\tstring session_id \"Session UUID\"\n\t\tstring user_id \"UUID of user\"\n\t}\n```\n\n## Passkeys Flows\n\nAny user can have any username they want in this passkeys demo. The client browser generates the user id that will belong to that username, and that user id (which is an uuid v4) is the only piece of information that's stored about the user, along with their public key, and optional attestation data.\n\nSince there's no identifiable user information, this can be considered an anonymous passkey implementation. As such, you'd be missing a way of keeping in touch with your users were you to implement the same demo.\n\n### Attestation\n\n```mermaid\nsequenceDiagram\n\tparticipant A as Authenticator\n\tparticipant C as Client\n\tparticipant S as Server\n\n\n\tnote over C, S: API /attestation/generate\n\tC -\u003e\u003e S: Get a challenge\n\tS --\u003e\u003e C: Receive challenge\n\n\tC -\u003e\u003e A: Generate a key pair\n\tnote right of A: Authenticator stores private key\n\tA --\u003e\u003e C: Return public key\n\n\tnote over C, S: API /attestation/store\n\tC -\u003e\u003e S: Send pubkey and challenge\n\tnote left of S: Store pubkey\n\tS --\u003e\u003e C: Success\n```\n\n### Assertion\n\n```mermaid\nsequenceDiagram\n\tparticipant A as Authenticator\n\tparticipant C as Client\n\tparticipant S as Server\n\n\tnote over C, S: API /assertion/generate\n\tC -\u003e\u003e S: Get a challenge\n\tS --\u003e\u003e C: Receive challenge\n\n\tC -\u003e\u003e A: Send challenge to use for signing\n\tA --\u003e\u003e C: Return signature\n\n\tnote over C, S: API /assertion/verify\n\tC -\u003e\u003e S: Send signature\n\tnote left of S: Server verifies signature\n\tS --\u003e\u003e C: Successfully verified\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnealfennimore%2Fpasskeys","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnealfennimore%2Fpasskeys","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnealfennimore%2Fpasskeys/lists"}