{"id":13703006,"url":"https://github.com/Yubico/java-webauthn-server","last_synced_at":"2025-05-05T07:30:33.122Z","repository":{"id":33275203,"uuid":"132609722","full_name":"Yubico/java-webauthn-server","owner":"Yubico","description":"Server-side Web Authentication library for Java https://www.w3.org/TR/webauthn/#rp-operations","archived":false,"fork":false,"pushed_at":"2025-04-28T16:05:29.000Z","size":9937,"stargazers_count":502,"open_issues_count":19,"forks_count":152,"subscribers_count":46,"default_branch":"main","last_synced_at":"2025-04-28T17:23:45.925Z","etag":null,"topics":["authentication","fido","fido-u2f","java","u2f","webauthn"],"latest_commit_sha":null,"homepage":null,"language":"Scala","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Yubico.png","metadata":{"files":{"readme":"README","changelog":"NEWS","contributing":null,"funding":null,"license":"COPYING","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,"zenodo":null}},"created_at":"2018-05-08T13:01:39.000Z","updated_at":"2025-04-28T14:36:32.000Z","dependencies_parsed_at":"2023-11-09T11:15:19.210Z","dependency_job_id":"b936ab58-0347-4c0e-910c-c3ad184e1dda","html_url":"https://github.com/Yubico/java-webauthn-server","commit_stats":null,"previous_names":[],"tags_count":117,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Yubico%2Fjava-webauthn-server","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Yubico%2Fjava-webauthn-server/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Yubico%2Fjava-webauthn-server/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Yubico%2Fjava-webauthn-server/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Yubico","download_url":"https://codeload.github.com/Yubico/java-webauthn-server/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252458316,"owners_count":21751014,"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","fido","fido-u2f","java","u2f","webauthn"],"created_at":"2024-08-02T21:00:48.681Z","updated_at":"2025-05-05T07:30:33.114Z","avatar_url":"https://github.com/Yubico.png","language":"Scala","readme":"java-webauthn-server\n====================\n:toc:\n:toc-placement: macro\n:toc-title:\n:idprefix:\n:idseparator: -\n\nimage:https://github.com/Yubico/java-webauthn-server/workflows/build/badge.svg[\"Build Status\", link=\"https://github.com/Yubico/java-webauthn-server/actions\"]\nimage:https://img.shields.io/endpoint?url=https%3A%2F%2FYubico.github.io%2Fjava-webauthn-server%2Fcoverage-badge.json[\"Mutation test coverage\", link=\"https://Yubico.github.io/java-webauthn-server/\"]\nimage:https://github.com/Yubico/java-webauthn-server/actions/workflows/release-verify-signatures.yml/badge.svg[\"Binary reproducibility\", link=\"https://github.com/Yubico/java-webauthn-server/actions/workflows/release-verify-signatures.yml\"]\n\nServer-side https://www.w3.org/TR/webauthn/[Web Authentication] library for\nJava. Provides implementations of the\nhttps://www.w3.org/TR/webauthn/#sctn-rp-operations[Relying Party operations] required\nfor a server to support Web Authentication, including https://passkeys.dev/[passkey authentication].\n\n\n[WARNING]\n.*Psychic signatures in Java*\n==========\nIn April 2022, link:https://neilmadden.blog/2022/04/19/psychic-signatures-in-java/[CVE-2022-21449]\nwas disclosed in Oracle's OpenJDK (and other JVMs derived from it) which can impact applications using java-webauthn-server.\nThe impact is that for the most common type of WebAuthn credential, invalid signatures are accepted as valid,\nallowing authentication bypass for users with such a credential.\nPlease read link:https://openjdk.java.net/groups/vulnerability/advisories/2022-04-19[Oracle's advisory]\nand make sure you are not using one of the impacted OpenJDK versions.\nIf you are, we urge you to upgrade your Java deployment to a version that is safe.\n==========\n\n\n*Table of contents*\n\n:toclevels: 3\ntoc::[]\n\n\n== Features\n\n- Generates request objects suitable as parameters to\n  `navigator.credentials.create()` and `.get()`\n- Performs all necessary\n  https://www.w3.org/TR/webauthn/#sctn-rp-operations[validation logic] on the\n  response from the client\n- No mutable state or side effects - everything (except builders) is thread safe\n- Optionally integrates with an \"attestation trust source\" to verify\n  https://www.w3.org/TR/webauthn/#sctn-attestation[authenticator attestations]\n- Reproducible builds: release signatures match fresh builds from source. See\n  \u003c\u003creproducible-builds\u003e\u003e below.\n\n\n=== Non-features\n\nThis library has no concept of accounts, sessions, permissions or identity\nfederation, and it is not an authentication framework; it only deals with\nexecuting the WebAuthn authentication mechanism. Sessions, account management\nand other higher level concepts can make use of this authentication mechanism,\nbut the authentication mechanism alone does not make a security system.\n\n\n== Dependency configuration\n\nMaven:\n\n----------\n\u003cdependency\u003e\n  \u003cgroupId\u003ecom.yubico\u003c/groupId\u003e\n  \u003cartifactId\u003ewebauthn-server-core\u003c/artifactId\u003e\n  \u003cversion\u003e2.6.0\u003c/version\u003e\n  \u003cscope\u003ecompile\u003c/scope\u003e\n\u003c/dependency\u003e\n----------\n\nGradle:\n\n----------\nimplementation(\"com.yubico:webauthn-server-core:2.6.0\")\n----------\n\nNOTE: You may need additional dependencies with JCA providers to support some signature algorithms.\nIn particular, OpenJDK 14 and earlier does not include providers for the EdDSA family of algorithms.\nThe library will log warnings if you try to configure it for algorithms with no JCA provider available.\n\n\n=== Semantic versioning\n\nThis library uses link:https://semver.org/[semantic versioning].\nThe public API consists of all public classes, methods and fields in the `com.yubico.webauthn` package and its subpackages,\ni.e., everything covered by the\nlink:https://developers.yubico.com/java-webauthn-server/JavaDoc/webauthn-server-core/2.6.0/com/yubico/webauthn/package-summary.html[Javadoc],\n*with the exception* of features annotated with a `@Deprecated` annotation and a\n`@deprecated EXPERIMENTAL:` tag in JavaDoc.\nSuch features are considered unstable and may receive breaking changes without a\nmajor version increase.\n\nPackage-private classes and methods are NOT part of the public API.\nThe `com.yubico:yubico-util` module is NOT part of the public API.\nBreaking changes to these will NOT be reflected in version numbers.\n\n\n=== Additional modules\n\nIn addition to the main `webauthn-server-core` module, there is also:\n\n- link:webauthn-server-attestation[`webauthn-server-attestation`]: Integration with the https://fidoalliance.org/metadata/[FIDO Metadata Service]\n  for retrieving and selecting trust roots to use for verifying\n  https://www.w3.org/TR/2021/REC-webauthn-2-20210408/#sctn-attestation[attestation statements].\n\n\n== Documentation\n\nSee the\nlink:https://developers.yubico.com/java-webauthn-server/JavaDoc/webauthn-server-core/2.6.0/com/yubico/webauthn/package-summary.html[Javadoc]\nfor in-depth API documentation.\n\n\n== Getting started\n\nUsing this library comes in two parts: the server side and the client side.\nThe server side involves:\n\n 1. Implement the\n    link:https://developers.yubico.com/java-webauthn-server/JavaDoc/webauthn-server-core/2.6.0/com/yubico/webauthn/CredentialRepository.html[`CredentialRepository`]\n    interface with your database access logic.\n 2. Instantiate the\n    link:https://developers.yubico.com/java-webauthn-server/JavaDoc/webauthn-server-core/2.6.0/com/yubico/webauthn/RelyingParty.html[`RelyingParty`]\n    class.\n 3. Use the\n    link:https://developers.yubico.com/java-webauthn-server/JavaDoc/webauthn-server-core/2.6.0/com/yubico/webauthn/RelyingParty.html#startRegistration(com.yubico.webauthn.StartRegistrationOptions)[`RelyingParty.startRegistration(...)`]\n    and\n    link:https://developers.yubico.com/java-webauthn-server/JavaDoc/webauthn-server-core/2.6.0/com/yubico/webauthn/RelyingParty.html#finishRegistration(com.yubico.webauthn.FinishRegistrationOptions)[`RelyingParty.finishRegistration(...)`]\n    methods to perform registration ceremonies.\n 4. Use the\n    link:https://developers.yubico.com/java-webauthn-server/JavaDoc/webauthn-server-core/2.6.0/com/yubico/webauthn/RelyingParty.html#startAssertion(com.yubico.webauthn.StartAssertionOptions)[`RelyingParty.startAssertion(...)`]\n    and\n    link:https://developers.yubico.com/java-webauthn-server/JavaDoc/webauthn-server-core/2.6.0/com/yubico/webauthn/RelyingParty.html#finishAssertion(com.yubico.webauthn.FinishAssertionOptions)[`RelyingParty.finishAssertion(...)`]\n    methods to perform authentication ceremonies.\n 5. Optionally use additional features: passkeys, passwordless multi-factor authentication, credential backup state.\n\nThe client side involves:\n\n 1. Call `navigator.credentials.create()` or `.get()`,\n    passing the result from `RelyingParty.startRegistration(...)` or `.startAssertion(...)` as the argument.\n 2. Encode the result of the successfully resolved promise and return it to the server.\n    For this you need some way to encode `Uint8Array` values;\n    this guide will use GitHub's link:https://github.com/github/webauthn-json[webauthn-json] library.\n\nExample code is given below.\nFor more detailed example usage, see\nlink:webauthn-server-demo[`webauthn-server-demo`] for a complete demo server.\n\n\n=== 1. Implement a `CredentialRepository`\n\nThe\nlink:https://developers.yubico.com/java-webauthn-server/JavaDoc/webauthn-server-core/2.6.0/com/yubico/webauthn/CredentialRepository.html[`CredentialRepository`]\ninterface abstracts your database in a database-agnostic way.\nThe concrete implementation will be different for every project, but you can use\nlink:https://github.com/Yubico/java-webauthn-server/blob/main/webauthn-server-demo/src/main/java/demo/webauthn/InMemoryRegistrationStorage.java[`InMemoryRegistrationStorage`]\nas a simple example.\n\n=== 2. Instantiate a `RelyingParty`\n\nThe\nlink:https://developers.yubico.com/java-webauthn-server/JavaDoc/webauthn-server-core/2.6.0/com/yubico/webauthn/RelyingParty.html[`RelyingParty`]\nclass is the main entry point to the library.\nYou can instantiate it using its builder methods,\npassing in your\nlink:https://developers.yubico.com/java-webauthn-server/JavaDoc/webauthn-server-core/2.6.0/com/yubico/webauthn/CredentialRepository.html[`CredentialRepository`]\nimplementation (called `MyCredentialRepository` here) as an argument:\n\n[source,java]\n----------\nRelyingPartyIdentity rpIdentity = RelyingPartyIdentity.builder()\n    .id(\"example.com\")  // Set this to a parent domain that covers all subdomains\n                        // where users' credentials should be valid\n    .name(\"Example Application\")\n    .build();\n\nRelyingParty rp = RelyingParty.builder()\n    .identity(rpIdentity)\n    .credentialRepository(new MyCredentialRepository())\n    .build();\n----------\n\n=== 3. Registration\n\nA registration ceremony consists of 5 main steps:\n\n 1. Generate registration parameters using\n    link:https://developers.yubico.com/java-webauthn-server/JavaDoc/webauthn-server-core/2.6.0/com/yubico/webauthn/RelyingParty.html#startRegistration(com.yubico.webauthn.StartRegistrationOptions)[`RelyingParty.startRegistration(...)`].\n 2. Send registration parameters to the client and call\n    https://developer.mozilla.org/en-US/docs/Web/API/CredentialsContainer/create[`navigator.credentials.create()`].\n 3. With `cred` as the result of the successfully resolved promise,\n    call https://www.w3.org/TR/webauthn-2/#ref-for-dom-publickeycredential-getclientextensionresults[`cred.getClientExtensionResults()`]\n    and https://www.w3.org/TR/webauthn-2/#ref-for-dom-authenticatorattestationresponse-gettransports[`cred.response.getTransports()`]\n    and return their results along with `cred` to the server.\n 4. Validate the response using\n    link:https://developers.yubico.com/java-webauthn-server/JavaDoc/webauthn-server-core/2.6.0/com/yubico/webauthn/RelyingParty.html#finishRegistration(com.yubico.webauthn.FinishRegistrationOptions)[`RelyingParty.finishRegistration(...)`].\n 5. Update your database using the `finishRegistration` output.\n\nThis example uses GitHub's link:https://github.com/github/webauthn-json[webauthn-json] library to do both (2) and (3) in one function call.\n\nFirst, generate registration parameters and send them to the client:\n\n[source,java]\n----------\nOptional\u003cUserIdentity\u003e findExistingUser(String username) { /* ... */ }\n\nPublicKeyCredentialCreationOptions request = rp.startRegistration(\n  StartRegistrationOptions.builder()\n    .user(\n        findExistingUser(\"alice\")\n            .orElseGet(() -\u003e {\n                byte[] userHandle = new byte[64];\n                random.nextBytes(userHandle);\n                return UserIdentity.builder()\n                    .name(\"alice\")\n                    .displayName(\"Alice Hypothetical\")\n                    .id(new ByteArray(userHandle))\n                    .build();\n            })\n    )\n    .build());\n\nString credentialCreateJson = request.toCredentialsCreateJson();\nreturn credentialCreateJson;  // Send to client\n----------\n\nYou will need to keep this\nlink:https://developers.yubico.com/java-webauthn-server/JavaDoc/webauthn-server-core/2.6.0/com/yubico/webauthn/data/PublicKeyCredentialCreationOptions.html[`PublicKeyCredentialCreationOptions`]\nobject in temporary storage\nso you can also pass it into\nlink:https://developers.yubico.com/java-webauthn-server/JavaDoc/webauthn-server-core/2.6.0/com/yubico/webauthn/RelyingParty.html#finishRegistration(com.yubico.webauthn.FinishRegistrationOptions)[`RelyingParty.finishRegistration(...)`]\nlater.\nIf needed, you can use the\nlink:https://developers.yubico.com/java-webauthn-server/JavaDoc/webauthn-server-core/2.6.0/com/yubico/webauthn/data/PublicKeyCredentialCreationOptions.html#toJson()[`toJson()`]\nand\nlink:https://developers.yubico.com/java-webauthn-server/JavaDoc/webauthn-server-core/2.6.0/com/yubico/webauthn/data/PublicKeyCredentialCreationOptions.html#fromJson(java.lang.String)[`fromJson(String)`]\nmethods to serialize and deserialize the value for storage.\n\nNow call the WebAuthn API on the client side:\n\n[source,javascript]\n----------\nimport * as webauthnJson from \"@github/webauthn-json\";\n\n// Make the call that returns the credentialCreateJson above\nconst credentialCreateOptions = await fetch(/* ... */).then(resp =\u003e resp.json());\n\n// Call WebAuthn ceremony using webauthn-json wrapper\nconst publicKeyCredential = await webauthnJson.create(credentialCreateOptions);\n\n// Return encoded PublicKeyCredential to server\nfetch(/* ... */, { body: JSON.stringify(publicKeyCredential) });\n----------\n\nValidate the response on the server side:\n\n[source,java]\n----------\nString publicKeyCredentialJson = /* ... */;     // publicKeyCredential from client\nPublicKeyCredential\u003cAuthenticatorAttestationResponse, ClientRegistrationExtensionOutputs\u003e pkc =\n    PublicKeyCredential.parseRegistrationResponseJson(publicKeyCredentialJson);\n\ntry {\n    RegistrationResult result = rp.finishRegistration(FinishRegistrationOptions.builder()\n        .request(request)  // The PublicKeyCredentialCreationOptions from startRegistration above\n                           // NOTE: Must be stored in server memory or otherwise protected against tampering\n        .response(pkc)\n        .build());\n} catch (RegistrationFailedException e) { /* ... */ }\n----------\n\nFinally, if the previous step was successful, store the new credential in your database.\nHere is an example of things you will likely want to store:\n\n[source,java]\n----------\nstoreCredential(              // Some database access method of your own design\n  \"alice\",                    // Username or other appropriate user identifier\n  result.getKeyId(),          // Credential ID and transports for allowCredentials\n  result.getPublicKeyCose(),  // Public key for verifying authentication signatures\n  result.getSignatureCount(), // Initial signature counter value\n  result.isDiscoverable(),    // Is this a passkey?\n  result.isBackupEligible(),  // Can this credential be backed up (synced)?\n  result.isBackedUp(),        // Is this credential currently backed up?\n  pkc.getResponse().getAttestationObject(), // Store attestation object for future reference\n  pkc.getResponse().getClientDataJSON()     // Store client data for re-verifying signature if needed\n);\n----------\n\n\n[#getting-started-authentication]\n=== 4. Authentication\n\nLike registration ceremonies, an authentication ceremony consists of 5 main steps:\n\n 1. Generate authentication parameters using\n    link:https://developers.yubico.com/java-webauthn-server/JavaDoc/webauthn-server-core/2.6.0/com/yubico/webauthn/RelyingParty.html#startAssertion(com.yubico.webauthn.StartAssertionOptions)[`RelyingParty.startAssertion(...)`].\n 2. Send authentication parameters to the client, call\n    https://developer.mozilla.org/en-US/docs/Web/API/CredentialsContainer/get[`navigator.credentials.get()`]\n    and return the response.\n 3. With `cred` as the result of the successfully resolved promise, call\n    https://www.w3.org/TR/webauthn-2/#ref-for-dom-publickeycredential-getclientextensionresults[`cred.getClientExtensionResults()`]\n    and return the result along with `cred` to the server.\n 4. Validate the response using\n    link:https://developers.yubico.com/java-webauthn-server/JavaDoc/webauthn-server-core/2.6.0/com/yubico/webauthn/RelyingParty.html#finishAssertion(com.yubico.webauthn.FinishAssertionOptions)[`RelyingParty.finishAssertion(...)`].\n 5. Update your database using the `finishAssertion` output, and act upon the result (for example, grant login access).\n\nThis example uses GitHub's link:https://github.com/github/webauthn-json[webauthn-json] library to do both (2) and (3) in one function call.\n\nFirst, generate authentication parameters and send them to the client:\n\n[source,java]\n----------\nAssertionRequest request = rp.startAssertion(StartAssertionOptions.builder()\n    .username(\"alice\")     // Or .userHandle(ByteArray) if preferred\n    .build());\nString credentialGetJson = request.toCredentialsGetJson();\nreturn credentialGetJson;  // Send to client\n----------\n\nAgain, you will need to keep this\nlink:https://developers.yubico.com/java-webauthn-server/JavaDoc/webauthn-server-core/2.6.0/com/yubico/webauthn/AssertionRequest.html[`AssertionRequest`]\nobject in temporary storage\nso you can also pass it into\nlink:https://developers.yubico.com/java-webauthn-server/JavaDoc/webauthn-server-core/2.6.0/com/yubico/webauthn/RelyingParty.html#finishAssertion(com.yubico.webauthn.FinishAssertionOptions)[`RelyingParty.finishAssertion(...)`]\nlater.\nIf needed, you can use the\nlink:https://developers.yubico.com/java-webauthn-server/JavaDoc/webauthn-server-core/2.6.0/com/yubico/webauthn/AssertionRequest.html#toJson()[`toJson()`]\nand\nlink:https://developers.yubico.com/java-webauthn-server/JavaDoc/webauthn-server-core/2.6.0/com/yubico/webauthn/AssertionRequest.html#fromJson(java.lang.String)[`fromJson(String)`]\nmethods to serialize and deserialize the value for storage.\n\nNow call the WebAuthn API on the client side:\n\n[source,javascript]\n----------\nimport * as webauthnJson from \"@github/webauthn-json\";\n\n// Make the call that returns the credentialGetJson above\nconst credentialGetOptions = await fetch(/* ... */).then(resp =\u003e resp.json());\n\n// Call WebAuthn ceremony using webauthn-json wrapper\nconst publicKeyCredential = await webauthnJson.get(credentialGetOptions);\n\n// Return encoded PublicKeyCredential to server\nfetch(/* ... */, { body: JSON.stringify(publicKeyCredential) });\n----------\n\nValidate the response on the server side:\n\n[source,java]\n----------\nString publicKeyCredentialJson = /* ... */;  // publicKeyCredential from client\nPublicKeyCredential\u003cAuthenticatorAssertionResponse, ClientAssertionExtensionOutputs\u003e pkc =\n    PublicKeyCredential.parseAssertionResponseJson(publicKeyCredentialJson);\n\ntry {\n    AssertionResult result = rp.finishAssertion(FinishAssertionOptions.builder()\n        .request(request)  // The PublicKeyCredentialRequestOptions from startAssertion above\n        .response(pkc)\n        .build());\n\n    if (result.isSuccess()) {\n        return result.getUsername();\n    }\n} catch (AssertionFailedException e) { /* ... */ }\nthrow new RuntimeException(\"Authentication failed\");\n----------\n\nFinally, if the previous step was successful, update your database using the\nlink:https://developers.yubico.com/java-webauthn-server/JavaDoc/webauthn-server-core/2.6.0/com/yubico/webauthn/AssertionResult.html[`AssertionResult`].\nMost importantly, you should update the signature counter. That might look something like this:\n\n[source,java]\n----------\nupdateCredential(              // Some database access method of your own design\n  \"alice\",                     // Query by username or other appropriate user identifier\n  result.getCredentialId(),    // Query by credential ID of the credential used\n  result.getSignatureCount(),  // Set new signature counter value\n  result.isBackedUp(),         // Set new backup state flag\n  Clock.systemUTC().instant()  // Set time of last use (now)\n);\n----------\n\nThen do whatever else you need - for example, initiate a user session.\n\n\n=== 5. Optional features: passkeys, multi-factor, backup state\n\nWebAuthn supports a number of additional features beyond the basics:\n\n- \u003c\u003cpasskeys,Passkeys\u003e\u003e: passwordless, username-less authentication.\n  link:https://passkey.org[Try it on passkey.org!]\n- \u003c\u003cuser-verification,User verification\u003e\u003e: passwordless, streamlined multi-factor authentication.\n- \u003c\u003cautofill-ui,Autofill UI\u003e\u003e: Unintrusive passkey integration in traditional login forms.\n- \u003c\u003ccredential-backup-state,Credential backup state\u003e\u003e: hints on how vulnerable the user is to authenticator loss.\n\n\n[#passkeys]\n==== Passkeys: passwordless, username-less authentication\n\nA https://passkeys.dev/[passkey] is a WebAuthn credential that can simultaneously both _identify_ and _authenticate_ the user.\nThis is also called a link:https://www.w3.org/TR/2021/REC-webauthn-2-20210408/#discoverable-credential[discoverable credential].\nBy default, credentials are created non-discoverable, which means the server\nmust list them in the\nhttps://www.w3.org/TR/webauthn/#dom-publickeycredentialrequestoptions-allowcredentials[`allowCredentials`]\nparameter before the user can use them to authenticate.\nThis is typically because the credential private key is not stored within the authenticator,\nbut instead encoded into one of the credential IDs in `allowCredentials`.\nThis way even a small hardware authenticator can have an unlimited credential capacity,\nbut with the drawback that the user must first identify themself to the server\nso the server can retrieve the correct `allowCredentials` list.\n\nPasskeys are instead stored within the authenticator, and also include the user's\nlink:https://www.w3.org/TR/2021/REC-webauthn-2-20210408/#user-handle[user handle]\nin addition to the credential ID.\nThis way the user can be both identified and authenticated simultaneously.\nMany passkey-capable authenticators also offer a credential sync mechanism\nto allow one passkey to be used on multiple devices.\n\nPasskeys can be created by setting the\nlink:https://developers.yubico.com/java-webauthn-server/JavaDoc/webauthn-server-core/2.6.0/com/yubico/webauthn/StartRegistrationOptions.StartRegistrationOptionsBuilder.html#authenticatorSelection(com.yubico.webauthn.data.AuthenticatorSelectionCriteria)[`authenticatorSelection`].link:https://developers.yubico.com/java-webauthn-server/JavaDoc/webauthn-server-core/2.6.0/com/yubico/webauthn/data/AuthenticatorSelectionCriteria.AuthenticatorSelectionCriteriaBuilder.html#residentKey(com.yubico.webauthn.data.ResidentKeyRequirement)[`residentKey`]\noption to\nlink:https://developers.yubico.com/java-webauthn-server/JavaDoc/webauthn-server-core/2.6.0/com/yubico/webauthn/data/ResidentKeyRequirement.html#REQUIRED[`REQUIRED`]:\n\n[source,java]\n----------\nPublicKeyCredentialCreationOptions request = rp.startRegistration(\n  StartRegistrationOptions.builder()\n    .user(/* ... */)\n    .authenticatorSelection(AuthenticatorSelectionCriteria.builder()\n        .residentKey(ResidentKeyRequirement.REQUIRED)\n        .build())\n    .build());\n----------\n\nThe username can then be omitted when starting an authentication ceremony:\n\n[source,java]\n----------\nAssertionRequest request = rp.startAssertion(StartAssertionOptions.builder().build());\n----------\n\nSome authenticators might create passkeys even if not required, and setting\nthe\nlink:https://developers.yubico.com/java-webauthn-server/JavaDoc/webauthn-server-core/2.6.0/com/yubico/webauthn/data/AuthenticatorSelectionCriteria.AuthenticatorSelectionCriteriaBuilder.html#residentKey(com.yubico.webauthn.data.ResidentKeyRequirement)[`residentKey`]\noption to\nlink:https://developers.yubico.com/java-webauthn-server/JavaDoc/webauthn-server-core/2.6.0/com/yubico/webauthn/data/ResidentKeyRequirement.html#PREFERRED[`PREFERRED`]\nwill create a passkey if the authenticator supports it.\nThe\nlink:https://developers.yubico.com/java-webauthn-server/JavaDoc/webauthn-server-core/2.6.0/com/yubico/webauthn/RegistrationResult.html#isDiscoverable()[`RegistrationResult.isDiscoverable()`]\nmethod can be used to determine whether the created credential is a passkey.\nThis requires the\nlink:https://developers.yubico.com/java-webauthn-server/JavaDoc/webauthn-server-core/2.6.0/com/yubico/webauthn/data/RegistrationExtensionInputs.RegistrationExtensionInputsBuilder.html#credProps()[`credProps` extension]\nto be enabled, which it is by default.\n\n\n[#user-verification]\n==== User verification: passwordless multi-factor authentication\n\nlink:https://passkeys.dev/docs/reference/terms/#user-verification-uv[User verification]\ncan be enforced independently per authentication ceremony:\n\n[source,java]\n----------\nAssertionRequest request = rp.startAssertion(StartAssertionOptions.builder()\n    .username(\"alice\")\n    .userVerification(UserVerificationRequirement.REQUIRED)\n    .build());\n----------\n\nThen\nlink:https://developers.yubico.com/java-webauthn-server/JavaDoc/webauthn-server-core/2.6.0/com/yubico/webauthn/RelyingParty.html#finishAssertion(com.yubico.webauthn.FinishAssertionOptions)[`RelyingParty.finishAssertion(...)`]\nwill enforce that user verification was performed.\nHowever, there is no guarantee that the user's authenticator will support this\nunless the user has some credential created with the\nlink:https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialcreationoptions-authenticatorselection[`authenticatorSelection`].link:https://www.w3.org/TR/webauthn-2/#dom-authenticatorselectioncriteria-userverification[`userVerification`]\noption set:\n\n[source,java]\n----------\nPublicKeyCredentialCreationOptions request = rp.startRegistration(\n  StartRegistrationOptions.builder()\n    .user(/* ... */)\n    .authenticatorSelection(AuthenticatorSelectionCriteria.builder()\n        .userVerification(UserVerificationRequirement.REQUIRED)\n        .build())\n    .build());\n----------\n\nYou can also request that user verification be used if possible, but is not required:\n\n[source,java]\n----------\nPublicKeyCredentialCreationOptions request = rp.startRegistration(\n  StartRegistrationOptions.builder()\n    .user(/* ... */)\n    .authenticatorSelection(AuthenticatorSelectionCriteria.builder()\n        .userVerification(UserVerificationRequirement.PREFERRED)\n        .build())\n    .build());\n\nAssertionRequest request = rp.startAssertion(StartAssertionOptions.builder()\n    .username(\"alice\")\n    .userVerification(UserVerificationRequirement.PREFERRED)\n    .build());\n----------\n\nIn this case\nlink:https://developers.yubico.com/java-webauthn-server/JavaDoc/webauthn-server-core/2.6.0/com/yubico/webauthn/RelyingParty.html#finishRegistration(com.yubico.webauthn.FinishRegistrationOptions)[`RelyingParty.finishRegistration(...)`]\nand\nlink:https://developers.yubico.com/java-webauthn-server/JavaDoc/webauthn-server-core/2.6.0/com/yubico/webauthn/RelyingParty.html#finishAssertion(com.yubico.webauthn.FinishAssertionOptions)[`RelyingParty.finishAssertion(...)`]\nwill NOT enforce user verification,\nbut instead the `isUserVerified()` method of\nlink:https://developers.yubico.com/java-webauthn-server/JavaDoc/webauthn-server-core/2.6.0/com/yubico/webauthn/RegistrationResult.html[`RegistrationResult`]\nand\nlink:https://developers.yubico.com/java-webauthn-server/JavaDoc/webauthn-server-core/2.6.0/com/yubico/webauthn/AssertionResult.html[`AssertionResult`]\nwill tell whether user verification was used.\n\nFor example, you could prompt for a password as the second factor if `isUserVerified()` returns `false`:\n\n[source,java]\n----------\nAssertionResult result = rp.finishAssertion(/* ... */);\n\nif (result.isSuccess()) {\n    if (result.isUserVerified()) {\n        return successfulLogin(result.getUsername());\n    } else {\n        return passwordRequired(result.getUsername());\n    }\n}\n----------\n\nUser verification can be used with both discoverable credentials (passkeys) and non-discoverable credentials.\n\n\n[#autofill-ui]\n==== Using passkeys with autofill UI\n\nPasskeys on platform authenticators may also support the WebAuthn\nlink:https://passkeys.dev/docs/reference/terms/#autofill-ui[autofill UI], also known as \"conditional mediation\".\nThis can help onboard users who are unfamiliar with a fully username-less login flow,\nallowing a familiar username input field to opportunistically offer a shortcut using a passkey\nif the user has one on their device.\n\nThis library is compatible with the autofill UI but provides no server-side options for it,\nbecause the steps to enable it are taken on the front-end side.\nUsing autofill UI does not affect the response verification procedure.\n\nSee the link:https://passkeys.dev/docs/use-cases/bootstrapping/[guide on passkeys.dev]\nfor complete instructions on how to enable the autofill UI.\nIn particular you need to:\n\n- Add the credential request option `mediation: \"conditional\"`\nalongside the `publicKey` option generated by\nlink:https://developers.yubico.com/java-webauthn-server/JavaDoc/webauthn-server-core/2.6.0/com/yubico/webauthn/RelyingParty.html#startAssertion(com.yubico.webauthn.StartAssertionOptions)[`RelyingParty.startAssertion(...)`],\n- Add `autocomplete=\"username webauthn\"` to a username input field on the page, and\n- Call `navigator.credentials.get()` in the background.\n\nIf the Promise resolves, handle it like any other assertion response as described in\n\u003c\u003cgetting-started-authentication\u003e\u003e above.\n\nBecause of technical limitations, autofill UI is as of May 2023 only supported for platform credentials,\ni.e., passkeys stored on the user's computing devices.\nAutofill UI might support passkeys on external security keys in the future.\n\n\n[#credential-backup-state]\n==== Credential backup state\n\nSome authenticators may allow credentials to be backed up and/or synced between devices.\nThis capability and its current state is signaled via the\nlink:https://w3c.github.io/webauthn/#sctn-credential-backup[Credential Backup State] flags,\nwhich are available via the `isBackedUp()` and `isBackupEligible()` methods of\nlink:https://developers.yubico.com/java-webauthn-server/JavaDoc/webauthn-server-core/2.6.0/com/yubico/webauthn/RegistrationResult.html[`RegistrationResult`]\nand\nlink:https://developers.yubico.com/java-webauthn-server/JavaDoc/webauthn-server-core/2.6.0/com/yubico/webauthn/AssertionResult.html[`AssertionResult`].\nThese can be used as a hint about how vulnerable a user is to authenticator loss.\nIn particular, a user with only one credential which is not backed up\nmay risk getting locked out if they lose their authenticator.\n\n\n== Migrating from version `1.x`\n\nSee link:doc/Migrating_from_v1.adoc[the migration guide].\n\n\n== Migrating from U2F\n\nThis section is only relevant for applications that have user credentials registered via the\nlink:https://fidoalliance.org/specs/fido-u2f-v1.2-ps-20170411/fido-u2f-javascript-api-v1.2-ps-20170411.html[U2F JavaScript API].\nNew WebAuthn deployments can skip this section.\n\nThe WebAuthn API is backwards-compatible with U2F authenticators,\nand credentials registered via the U2F API will continue to work with the WebAuthn API with the right settings.\n\nTo migrate to using the WebAuthn API, you need to do the following:\n\n 1. Follow the link:#getting-started[Getting started] guide above to set up WebAuthn support in general.\n+\nNote that unlike a U2F AppID, the WebAuthn link:https://developers.yubico.com/java-webauthn-server/JavaDoc/webauthn-server-core/2.6.0/com/yubico/webauthn/data/RelyingPartyIdentity.RelyingPartyIdentityBuilder.html#id(java.lang.String)[RP ID]\nconsists of only the domain name of the AppID.\nWebAuthn does not support link:https://fidoalliance.org/specs/fido-u2f-v1.2-ps-20170411/fido-appid-and-facets-v1.2-ps-20170411.html[U2F Trusted Facet Lists].\n\n 2. Set the\n  link:https://developers.yubico.com/java-webauthn-server/JavaDoc/webauthn-server-core/2.6.0/com/yubico/webauthn/RelyingParty.RelyingPartyBuilder.html#appId(com.yubico.webauthn.extension.appid.AppId)[`appId()`]\n  setting on your\n  link:https://developers.yubico.com/java-webauthn-server/JavaDoc/webauthn-server-core/2.6.0/com/yubico/webauthn/RelyingParty.html[`RelyingParty`]\n  instance.\n  The argument to the `appid()` setting should be the same as you used for the `appId` argument to the\n  link:https://fidoalliance.org/specs/fido-u2f-v1.2-ps-20170411/fido-u2f-javascript-api-v1.2-ps-20170411.html#high-level-javascript-api[U2F `register` and `sign` functions].\n+\nThis will enable the link:https://www.w3.org/TR/2021/REC-webauthn-2-20210408/#sctn-appid-extension[`appid`]\nand link:https://www.w3.org/TR/2021/REC-webauthn-2-20210408/#sctn-appid-exclude-extension[`appidExclude`]\nextensions and configure the `RelyingParty` to accept the given AppId when verifying authenticator signatures.\n\n 3. Generate a link:https://www.w3.org/TR/2021/REC-webauthn-2-20210408/#user-handle[user handle]\n    for each existing user and store it in their account,\n    or decide on a method for deriving one deterministically from existing user attributes.\n    For example, if your user records are assigned UUIDs, you can use that UUID as the user handle.\n    You SHOULD NOT use a plain username or e-mail address, or hash of either, as the user handle -\n    for more on this, see the link:https://www.w3.org/TR/2021/REC-webauthn-2-20210408/#sctn-user-handle-privacy[User Handle Contents]\n    privacy consideration.\n\n 4. When your\n    link:https://developers.yubico.com/java-webauthn-server/JavaDoc/webauthn-server-core/2.6.0/com/yubico/webauthn/CredentialRepository.html[`CredentialRepository`]\n    creates a\n    link:https://developers.yubico.com/java-webauthn-server/JavaDoc/webauthn-server-core/2.6.0/com/yubico/webauthn/RegisteredCredential.html[`RegisteredCredential`]\n    for a U2F credential,\n    use the U2F key handle as the\n    link:https://developers.yubico.com/java-webauthn-server/JavaDoc/webauthn-server-core/2.6.0/com/yubico/webauthn/RegisteredCredential.RegisteredCredentialBuilder.html#credentialId(com.yubico.webauthn.data.ByteArray)[credential ID].\n    If you store key handles base64 encoded, you should decode them using\n    link:https://developers.yubico.com/java-webauthn-server/JavaDoc/webauthn-server-core/2.6.0/com/yubico/webauthn/data/ByteArray.html#fromBase64(java.lang.String)[`ByteArray.fromBase64`]\n    or\n    link:https://developers.yubico.com/java-webauthn-server/JavaDoc/webauthn-server-core/2.6.0/com/yubico/webauthn/data/ByteArray.html#fromBase64Url(java.lang.String)[`ByteArray.fromBase64Url`]\n    as appropriate before passing them to the `RegisteredCredential`.\n\n 5. When your `CredentialRepository` creates a `RegisteredCredential` for a U2F credential,\n    use the\n    link:https://developers.yubico.com/java-webauthn-server/JavaDoc/webauthn-server-core/2.6.0/com/yubico/webauthn/RegisteredCredential.RegisteredCredentialBuilder.html#publicKeyEs256Raw(com.yubico.webauthn.data.ByteArray)[`publicKeyEs256Raw()`]\n    method instead of link:https://developers.yubico.com/java-webauthn-server/JavaDoc/webauthn-server-core/2.6.0/com/yubico/webauthn/RegisteredCredential.RegisteredCredentialBuilder.html#publicKeyCose(com.yubico.webauthn.data.ByteArray)[`publicKeyCose()`]\n    to set the credential public key.\n\n 6. Replace calls to the U2F\n    link:https://fidoalliance.org/specs/fido-u2f-v1.2-ps-20170411/fido-u2f-javascript-api-v1.2-ps-20170411.html#high-level-javascript-api[`register`]\n    method with calls to `navigator.credentials.create()` as described in link:#getting-started[Getting started].\n\n 7. Replace calls to the U2F\n    link:https://fidoalliance.org/specs/fido-u2f-v1.2-ps-20170411/fido-u2f-javascript-api-v1.2-ps-20170411.html#high-level-javascript-api[`sign`]\n    method with calls to `navigator.credentials.get()` as described in link:#getting-started[Getting started].\n\nExisting U2F credentials should now work with the WebAuthn API.\n\nNote that new credentials registered on U2F authenticators via the WebAuthn API\nare NOT backwards compatible with the U2F JavaScript API.\n\n\n== Architecture\n\nThe library tries to place as few requirements on the overall application\narchitecture as possible. For this reason it is stateless and free from side\neffects, and does not directly interact with any database. This means it is\ndatabase agnostic and thread safe. The following diagram illustrates an example\narchitecture for an application using the library.\n\nimage::https://raw.githubusercontent.com/Yubico/java-webauthn-server/main/docs/img/demo-architecture.svg?sanitize=true[\"Example application architecture\",align=\"center\"]\n\nThe application manages all state and database access, and communicates with the\nlibrary via POJO representations of requests and responses. The following\ndiagram illustrates the data flow during a WebAuthn registration or\nauthentication ceremony.\n\nimage::https://raw.githubusercontent.com/Yubico/java-webauthn-server/main/docs/img/demo-sequence-diagram.svg?sanitize=true[\"WebAuthn ceremony sequence diagram\",align=\"center\"]\n\nIn this diagram, the *Client* is the user's browser and the application's\nclient-side scripts. The *Server* is the application and its business logic, the\n*Library* is this library, and the *Users* database stores registered WebAuthn\ncredentials.\n\n. The client requests to start the ceremony, for example by submitting a form.\n  The `username` may or may not be known at this point. For example, the user\n  might be requesting to create a new account, or we might be using\n  username-less authentication.\n\n. If the user does not already have a\n  https://www.w3.org/TR/webauthn/#user-handle[user handle], the application\n  creates one in some application-specific way.\n\n. The application may choose to authenticate the user with a password or the\n  like before proceeding.\n\n. The application calls one of the library's \"start\" methods to generate a\n  parameter object to be passed to `navigator.credentials.create()` or `.get()`\n  on the client.\n\n. The library generates a random challenge and an assortment of other arguments\n  depending on configuration set by the application.\n\n. If the `username` is known, the library uses a read-only database adapter\n  provided by the application to look up the user's credentials.\n\n. The returned list of https://www.w3.org/TR/webauthn/#credential-id[credential\n  IDs] is used to populate the\n  https://www.w3.org/TR/webauthn/#dom-publickeycredentialcreationoptions-excludecredentials[`excludeCredentials`]\n  or\n  https://www.w3.org/TR/webauthn/#dom-publickeycredentialrequestoptions-allowcredentials[`allowCredentials`]\n  parameter.\n\n. The library returns a `request` object which can be serialized to JSON and\n  passed as the `publicKey` argument to `navigator.credentials.create()` or\n  `.get()`. For registration ceremonies this will be a\n  https://www.w3.org/TR/webauthn/#dictdef-publickeycredentialcreationoptions[`PublicKeyCredentialCreationOptions`],\n  and for authentication ceremonies it will be a\n  https://www.w3.org/TR/webauthn/#dictdef-publickeycredentialrequestoptions[`PublicKeyCredentialRequestOptions`].\n  The application stores the `request` in temporary storage.\n\n. The application's client-side script runs `navigator.credentials.create()` or\n  `.get()` with `request` as the `publicKey` argument.\n\n. The user confirms the operation and the client returns a\n  https://www.w3.org/TR/webauthn/#public-key-credential[`PublicKeyCredential`]\n  object `response` to the application.\n\n. The application retrieves the `request` from temporary storage and passes\n  `request` and `response` to one of the library's \"finish\" methods to run the\n  response validation logic.\n\n. The library verifies that the `response` contents - challenge, origin, etc. -\n  are valid.\n\n. If this is an authentication ceremony, the library uses the database adapter\n  to look up the public key for the credential named in `response.id`.\n\n. The database adapter returns the public key.\n\n. The library verifies the authentication signature.\n\n. The library returns a POJO representation of the result of the ceremony. For\n  registration ceremonies, this will include the credential ID and public key of\n  the new credential. The application may opt in to also getting\n  information about the authenticator model and whether the authenticator\n  attestation is trusted. For authentication ceremonies, this will include the\n  username and user handle, the credential ID of the credential used, and the\n  new https://www.w3.org/TR/webauthn/#signature-counter[signature counter] value\n  for the credential.\n\n. The application inspects the result object and takes any appropriate actions\n  as defined by its business logic.\n\n. If the result is not satisfactory, the application reports failure to the\n  client.\n\n. If the result is satisfactory, the application proceeds with storing the new\n  credential if this is a registration ceremony.\n\n. If this is an authentication ceremony, the application updates the signature\n  counter stored in the database for the credential.\n\n. Finally, the application reports success and resumes its business logic.\n\n\n== Using attestation\n\nWebAuthn supports\nlink:https://www.w3.org/TR/2021/REC-webauthn-2-20210408/#sctn-attestation[authenticator attestation],\nwhich provides a way for the web service\nto request cryptographic proof of what authenticator the user is using.\nMost services do not need this, and it is disabled by default.\n\nThe link:webauthn-server-attestation[`webauthn-server-attestation` module]\nprovides optional additional features for working with attestation.\nSee the module documentation for more details.\n\nAlternatively, you can use the\nlink:https://developers.yubico.com/java-webauthn-server/JavaDoc/webauthn-server-core/2.6.0/com/yubico/webauthn/attestation/AttestationTrustSource.html[`AttestationTrustSource`]\ninterface to implement your own source of attestation root certificates\nand set it as the\nlink:https://developers.yubico.com/java-webauthn-server/JavaDoc/webauthn-server-core/2.6.0/com/yubico/webauthn/RelyingParty.RelyingPartyBuilder.html#attestationTrustSource(com.yubico.webauthn.attestation.AttestationTrustSource)[`attestationTrustSource`]\nfor your\nlink:https://developers.yubico.com/java-webauthn-server/JavaDoc/webauthn-server-core/2.6.0/com/yubico/webauthn/RelyingParty.html[`RelyingParty`]\ninstance.\nNote that depending on your JCA provider configuration, you may need to set the\nlink:https://developers.yubico.com/java-webauthn-server/JavaDoc/webauthn-server-core/2.6.0/com/yubico/webauthn/attestation/AttestationTrustSource.TrustRootsResult.TrustRootsResultBuilder.html#enableRevocationChecking(boolean)[`enableRevocationChecking`]\nand/or\nlink:https://developers.yubico.com/java-webauthn-server/JavaDoc/webauthn-server-core/2.6.0/com/yubico/webauthn/attestation/AttestationTrustSource.TrustRootsResult.TrustRootsResultBuilder.html#policyTreeValidator(java.util.function.Predicate)[`policyTreeValidator`]\nsettings for compatibility with some authenticators' attestation certificates.\nSee the JavaDoc for these settings for more information.\n\n\n== Building\n\nUse the included\nhttps://docs.gradle.org/current/userguide/gradle_wrapper.html[Gradle wrapper] to\nbuild the `.jar` artifact:\n\n[source,shell]\n----------\n$ ./gradlew :webauthn-server-core:jar\n----------\n\nThe output is built in the `webauthn-server-core/build/libs/` directory, and the\nversion is derived from the most recent Git tag. Builds done on a tagged commit\nwill have a plain `x.y.z` version number, while a build on any other commit will\nresult in a version number containing the abbreviated commit hash.\n\n\nTo run the tests:\n\n[source,shell]\n----------\n$ ./gradlew check\n----------\n\nTo run the http://pitest.org/[PIT mutation tests] (this may take upwards of 30\nminutes):\n\n[source,shell]\n----------\n$ ./gradlew pitest\n----------\n\n\n[#reproducible-builds]\n=== Reproducible builds\nStarting in version `1.4.0-RC2`, artifacts are built reproducibly. Fresh builds from\ntagged commits should therefore be verifiable by signatures from Maven Central\nand GitHub releases:\n\n[source,shell]\n----------\n$ git checkout 1.4.0-RC2\n$ ./gradlew :webauthn-server-core:jar\n\n$ wget https://repo1.maven.org/maven2/com/yubico/webauthn-server-core/1.4.0-RC2/webauthn-server-core-1.4.0-RC2.jar.asc\n$ gpg --verify webauthn-server-core-1.4.0-RC2.jar.asc webauthn-server-core/build/libs/webauthn-server-core-1.4.0-RC2.jar\n\n$ wget https://github.com/Yubico/java-webauthn-server/releases/download/1.4.0-RC2/webauthn-server-core-1.4.0-RC2.jar.asc\n$ gpg --verify webauthn-server-core-1.4.0-RC2.jar.asc webauthn-server-core/build/libs/webauthn-server-core-1.4.0-RC2.jar\n----------\n\nNote that building with a different JDK may produce a different artifact. To\nensure binary reproducibility, please build with the same JDK as specified in\nthe release notes. Reproducible builds also require building from a Git\nrepository, since the build embeds version number and Git commit ID into the\nbuilt artifacts.\n\nOfficial Yubico software signing keys are listed on the\nhttps://developers.yubico.com/Software_Projects/Software_Signing.html[Yubico\nDevelopers site].\n\n\n[#development]\n=== Development\n\nSee the link:https://github.com/Yubico/java-webauthn-server/blob/main/doc/development.md[developer docs].\n","funding_links":[],"categories":["Server Libraries","Library","安全"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FYubico%2Fjava-webauthn-server","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FYubico%2Fjava-webauthn-server","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FYubico%2Fjava-webauthn-server/lists"}