{"id":26022955,"url":"https://github.com/agrison/cljwebauthn","last_synced_at":"2025-06-25T18:04:35.655Z","repository":{"id":43877494,"uuid":"257404657","full_name":"agrison/cljwebauthn","owner":"agrison","description":"Webauthn for Clojure","archived":false,"fork":false,"pushed_at":"2024-05-28T14:29:28.000Z","size":46,"stargazers_count":14,"open_issues_count":3,"forks_count":3,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-02-17T14:18:03.543Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Clojure","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/agrison.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-04-20T21:10:48.000Z","updated_at":"2024-06-28T10:54:49.000Z","dependencies_parsed_at":"2022-09-25T00:00:52.863Z","dependency_job_id":null,"html_url":"https://github.com/agrison/cljwebauthn","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/agrison%2Fcljwebauthn","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/agrison%2Fcljwebauthn/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/agrison%2Fcljwebauthn/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/agrison%2Fcljwebauthn/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/agrison","download_url":"https://codeload.github.com/agrison/cljwebauthn/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":242194582,"owners_count":20087609,"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":[],"created_at":"2025-03-06T10:37:35.595Z","updated_at":"2025-03-06T10:37:36.174Z","avatar_url":"https://github.com/agrison.png","language":"Clojure","funding_links":[],"categories":[],"sub_categories":[],"readme":"# WebAuthn for Clojure\n\n[![cljdoc badge](https://cljdoc.org/badge/me.grison/cljwebauthn)](https://cljdoc.org/d/me.grison/cljwebauthn/CURRENT)\n\nThis library give you a Clojure wrapper over WebAuthn4J so that you can enable user registration and login functionality through WebAuthn in your Clojure backend / API.\n\nIts API is composed of 4 functions for:\n\n- preparing a registration challenge\n- register a user given the browser generated credentials\n- preparing a login challenge\n- login a user given the browser generated signature\n\n[![Alt text](https://img.youtube.com/vi/Q_2O13_yST4/0.jpg)](https://www.youtube.com/watch?v=Q_2O13_yST4)\n\nCurrent version of cljwebauthn uses version webauthn4j-core-0.19.0.RELEASE.\n\n## Dependency\n\nAdd the following dependency:\n\n```xml\n\u003cdependency\u003e\n   \u003cgroupId\u003eme.grison\u003c/groupId\u003e\n   \u003cartifactId\u003ecljwebauthn\u003c/artifactId\u003e\n   \u003cversion\u003e0.1.3\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n**deps.edn**\n```clojure\nme.grison/cljwebauthn {:mvn/version \"0.1.3\"}\n```\n\n**Leiningen/Boot**\n```clojure\n[me.grison/cljwebauthn \"0.1.2\"]\n```\n\n## API\n\n### `(prepare-registration user-identifier site-properties)`\n\nThis function will prepare a registration challenge for the client.\n\n- **input** \n  - **user-identifier**: can be anything that can identify a user, like an email or a nickname.\n  - **site-properties**: a map containing at least the following entries:\n    - **:site-id**: your website identifier (`grison.me`)\n    - **:site-name**: your website tagline (`My personal website`)\n    - **:protocol**: either `http` or `https`\n    - **:port**: the port your site is running on (`80`, `443`, ...)\n    - **:host**: your website hostname (`grison.me`)\n- **output**\n    - the necessary information needed on client side to bootstrap the navigator credentials\n\nExample:\n```clojure\n(cljwebauthn.core/prepare-registration \n    \"foo@bar.com\" \n    {:site-id   \"grison.me\",\n     :site-name \"Stuff and Thoughts about IT Stuff\",\n     :protocol  \"https\",\n     :port      443,\n     :host      \"grison.me\"})\n=\u003e {:rp        {:id  \"grison.me\"\n                :name \"Stuff and Thoughts about IT Stuff\"}\n    :user      {:id \"Zm9vQGJhci5jb20=\"}\n    :cred      [{:type \"public-key\"\n                 :alg  -7}]\n    :challenge challenge}\n```\n\n\n\n### `(register-user attestation site-properties save-authenticator)`\n\nThis function will validate the attestations generated by the client and call the `save-authenticator` function on success so that the API user can save the WebAuthn4J **authenticator** object for usage later on.\n\n- **input** \n  - **attestation**: a map containing at least the following entries:\n    - **:attestation**: base64 encoded value of the credential public key, an optional attestation certificate, and other metadata used also to validate the registration event. \n    - **:client-data**: base64 encoded value of the data passed from the browser to the authenticator in order to associate the new credential with the server and browser.\n    - **:challenge**: the challenge generated during the `prepare-registration` phase.\n  - **site-properties**: a map containing at least the following entries:\n    - **:site-id**: your website identifier (`grison.me`)\n    - **:site-name**: your website tagline (`My personal website`)\n    - **:protocol**: either `http` or `https`\n    - **:port**: the port your site is running on (`80`, `443`, ...)\n    - **:host**: your website hostname (`grison.me`)\n  - **save-authenticator**: a function whose job is to save the WebAuthn4J authenticator object, taking two parameters\n    - **user-id**: the user identifier\n    - **authenticator**: the WebAuthn4J authenticator object\n- **output**\n    - a map containing the user-identifier and the challenge in case of success\n    - `nil` in case the registration wasn't successful\n\nExample:\n```clojure\n(cljwebauthn.core/register-user \n    {:attestation \"o2NmbXRmcGFja2VkZ2F0dFN0bXSiY2FsZ...dbaqAkCY1nvQuI=\"\n     :client-data \"eyJjaGFsbGVuZ2UiOiJabTl2...ZWF0ZSJ9\"\n     :challenge   \"foobar\"}\n    {:site-id   \"grison.me\",\n     :site-name \"Stuff and Thoughts about IT Stuff\",\n     :protocol  \"https\",\n     :port      443,\n     :host      \"grison.me\"}\n     (fn [user-id authenticator] \n       ; save the authenticator for user-id somewhere\n     ))\n=\u003e {:user-id \"foo@bar.com\" :challenge \"foobar\"} \n```\n\n\n### `(prepare-login user-identifier get-authenticator)`\n\nThis function will prepare a login challenge for the client.\n\n- **input** \n  - **user-identifier**: can be anything that can identify a user, like an email or a nickname.\n  - **get-authenticator**: a function whose job is to retrieve the authenticator previously saved WebAuthn4J authenticator object.\n- **output**\n    - the necessary information needed on client side to bootstrap the navigator credentials\n\nExample:\n```clojure\n(cljwebauthn.core/prepare-login \n    \"foo@bar.com\" \n    (fn [user-id]\n      ; retrieve the authenticator for user-id\n    ))\n=\u003e {:challenge   \"foobar\"\n    :credentials [{:type \"public-key\"\n                   :id   \"AWcH5uwgu/phBRUWh6B9A2...tg54nA==\"}]}\n```\n\n\n\n### `(login-user assertion site-properties get-authenticator)`\n\nThis function will prepare a login challenge for the client.\n\n- **input** \n  - **assertion**: a map containing at least the following entries:\n    - **:credential-id**: base64 encoded value of the navigator credential raw id\n    - **:user-handle**: base64 encoded value of the user identifier\n    - **:authenticator-data**: base64 encoded value of the authenticator data which is similar to the authData received during registration, with the notable exception that the public key is not included here. It is another item used during authentication as source bytes to generate the assertion signature.\n    - **:client-data**: base64 encoded value of a collection of the data passed from the browser to the authenticator. It is one of the items used during authentication as the source bytes to generate the signature.\n    - **:signature**: base64 encoded value of the signature generated by the private key associated with this credential. \n    - **:challenge**: the challenge generated during the `prepare-login` phase. \n  - **site-properties**: a map containing at least the following entries:\n    - **:site-id**: your website identifier (`grison.me`)\n    - **:site-name**: your website tagline (`My personal website`)\n    - **:protocol**: either `http` or `https`\n    - **:port**: the port your site is running on (`80`, `443`, ...)\n    - **:host**: your website hostname (`grison.me`)\n  - **get-authenticator**: a function whose job is to retrieve the authenticator previously saved WebAuthn4J authenticator object.\n- **output**\n    - a map containing the user-identifier and the challenge in case of success\n    - `nil` in case the registration wasn't successful\n\n```clojure\n(cljwebauthn.core/login-user\n    {:credential-id      \"ARkFqKfCJaxgXG4m53c2y3zWpxSZGriN0sH...qt57yU=\"\n     :user-handle        \"Zm9vQGJhci5jb20=\"\n     :authenticator-data \"09CVCOxdEGxTwSc5mFML...3Wl3siTnwk0FXo82Tg==\"\n     :client-data        \"eyJjaGFsbGVuZ2UiOiJabTl2WW1...G4uZ2V0In0=\"\n     :signature          \"MEUCIQCkfqWpAhi7CRO0exa2wenWgDaakqJ..gv+gI1roY=\"\n     :challenge          \"foobar\"}\n   {:site-id   \"grison.me\",\n     :site-name \"Stuff and Thoughts about IT Stuff\",\n     :protocol  \"https\",\n     :port      443,\n     :host      \"grison.me\"}  \n   (fn [user-id] \n      ; retrieve the authenticator associated with user-id\n   ))\n=\u003e {:user-id \"foo@bar.com\" :challenge \"foobar\"} \n```\n\n## Testing\n\n### Running tests:\n\n```bash\nclj -M:test\n```\n\n### Running the sample test app:\n\n```bash\nclj -M:run-test\n```\n\nThen open [http://localhost:8080](http://localhost:8080).\n\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fagrison%2Fcljwebauthn","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fagrison%2Fcljwebauthn","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fagrison%2Fcljwebauthn/lists"}