The POST from webauthn.get would contain the following format. (newlines added for clarity.) POST /exampleapp/webauthn/finish_assertion user_auth_json={ "serviceOp": "webauthn.get", // or "webauthn.create". // If the serviceOp is "webauthn.create" then the RP needs to include a username in the response. "customData":{"exampleapp_request_id":"3a74f2b4-cff0-4f50-8076-2f5532a0d6f3"}, "assertionInfo":{ "credentials": [{ "type":"publicKey", "id":"K3xM080fiCDCkv412SdQ6--982rRf9i6NtDY0Jkv-AJZaCH9-MNs-ijV2y2OXKbxjzD3rXR05rmGF_jGQnXyPQ" }], "response":{ "authenticatorData":"xGzvgq0bVGR3WR0Aiwh1nsPm0uy085R0v+ppaZJdA7cBAAAANQ==", "clientDataJSON":"eyJjaGFsbGVuZ2UiOiJwakpQTWFvUUFFSEhKb0NtR0lVd3EtclZBc0JzRDY3Q2pCVDhMYXJwcEtjIiwiY2xpZW50RXh0ZW5zaW9ucyI6e30sImhhc2hBbGdvcml0aG0iOiJTSEEtMjU2Iiwib3JpZ2luIjoiaHR0cHM6Ly9kZW1vLnl1Ymljby5jb20iLCJ0eXBlIjoid2ViYXV0aG4uZ2V0In0=" }, "signatures": [{ "signature":"MEUCIHwdgFLpCi05C1SeqRIBEwM1iJr4HJu8H9YC49vlTd+OAiEAxGDHU0+zNrgk8eSrx9KD8bj6jqRiKdPNz2ANA7EShqI=" }], "clientExtensionResults":{},"transports":["usb"] } } In the case of failure the POST would contain something like: (3 POST parameters) POST /exampleapp/webauthn/finish_assertion exampleapp_request_id=3a74f2b4-cff0-4f50-8076-2f5532a0d6f3& assertionInfo={"error":"NotAllowedError","message":"The request is not allowed by the user agent or the platform in the current context, possibly because the user denied permission."} The endpoint.assertion_format default value is webauthn "webauthnAssertF1". This means to use the JSON/JS data structures from webauthn. "comment_20": "The entire customData object is copied into the POST to the RP." "comment_21": "Additional data can be added to the customData object.", "comment_23": "The exampleapp_request_id field is an example application-specific reference to server-side state.", "comment_24": "The server side may contain things like the username, a copy of the challenge, and probably where to redirect the user next.", "comment_30": "assertionOptions is (almost) a CredentialRequestOptions.", "comment_31": "But challenge is base64url encoded.", "comment_32": "The browser will (almost) call navigator.credentials.get(options) using the options as an argument.", "comment_40": "registrationOptions is (almost) a CredentialCreationOptions.", "comment_41": "But challenge is base64url encoded.", Comments about type:webauthn The webauthn.get data idea is adapted from "". For webauthn to work properly, the browser would probably need to render a button (in the page at a specified anchor or form). Clicking the button causes the browser to start the WebAuthn ceremony, and this may replace the button with a success/failure indicator after the ceremony finishes. When the form is submitted (or anchor is clicked), the browser would send a POST to the endpoint_uri. The exampleapp_request_id field is an example application-specific reference to server-side state, it contains things like the username, a copy of the challenge, and probably where to redirect the user next. The application can add any other fields to the POST that it needs. Add these to customData. The POST contains one (or more) name-value pairs, and ALL of the arguments contain JSON data. The name of the first argument of the POST is "user_auth_json" by default (but this can be changed). The assertionInfo is a JSON object. By default, the assertionInfo POST value uses the existing JSON/JS data structures from webauthn. Note that the request from the browser to the endpoint has the 'application/json' content-type. fetch_init.headers = { 'content-type': 'application/json' }; The primary new thing to add would be how (webauthn.create) and (webauthn.get) work. (i.e. How to create the POST values from the webauthn.create and webauthn.get input values.) (and how to en/decode the binary values to/from JSON). If the webauthn API was implemented with an actual FORM inside an HTML page, then the developer could use existing tools to customize how the data was delivered from the browser to the form action URI. In this case, all other details about data transport, URLs, redirects etc. would be left to the RP to implement however they please with already existing tools.

Capis Login lets people log into websites easily. It allows websites to use login buttons and anchors, and not forms.

Websites only need to include a couple HTML elements in the page. The browser can then connect to a standard type of "password manager", that will store and submit login keys to websites automatically.

Easier, More secure. Self-Hostable. Learn More.

Shortcut #1 -- Create sample Login data. Create a sample of LoginManagers, Badges and Login Items.
List of Operation Tests

Form Test 1. Create a custom Capis request. (Creates a custom Capis CapisAPI.callOptions value.)

(The form contents are not sent to the RP *as a form*. Instead, the contents are used to create a custom JSON callOptions value, and that is used to create a Capis request. The request is sent to the RP.)

Set the properties of the "callOptions" JSON object.
serviceOp: genUserId:
More properties:

Test of WebAuthn
Webauthn create new publicKey credential
Webauthn get publicKey assertion

Form Test 2. Form signing.

Test of form signing. Enter any data in the form below:

Code on GitHub at 12doors/Demo-RP.