Overview

Diagrams

<webauthn-spring-boot-starter> supports multiple flows

  • Authentication

authentication
  • Registration of a new user

registration
  • Registration of a new device

add device
  • Account recovery

recover

Resources

Register new user

Registration start

A POST request is used to start the Add User ceremony

Request structure

POST /registration/start HTTP/1.1
Content-Type: application/json;charset=UTF-8
Accept: application/json
Content-Length: 72
Host: localhost:8080

{"username":"newjunit","registrationAddToken":null,"recoveryToken":null}

Example response

HTTP/1.1 200 OK
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY
Content-Length: 648

{"status":"OK","registrationId":"Ey6LyiaXLwgM8wxeNIXnKQ==","publicKeyCredentialCreationOptions":{"rp":{"name":"localhost","id":"localhost","icon":{"empty":false,"present":true}},"user":{"name":"newjunit","displayName":"newjunit","id":"AAAAAAAAAAM","icon":{"empty":true,"present":false}},"challenge":"hZV-7roGRNnDzytShOxyDAvVTAHQTcVamfr2TYmDJZg","pubKeyCredParams":[{"alg":-7,"type":"public-key"},{"alg":-8,"type":"public-key"},{"alg":-257,"type":"public-key"}],"timeout":{"empty":true,"present":false},"excludeCredentials":{"empty":false,"present":true},"authenticatorSelection":{"empty":true,"present":false},"attestation":"none","extensions":{}}}

CURL request

$ curl 'http://localhost:8080/registration/start' -i -X POST \
    -H 'Content-Type: application/json;charset=UTF-8' \
    -H 'Accept: application/json' \
    -d '{"username":"newjunit","registrationAddToken":null,"recoveryToken":null}'

Register new user

Registration start

A POST request is used to start the Add User ceremony

Request structure

POST /registration/start HTTP/1.1
Content-Type: application/json;charset=UTF-8
Accept: application/json
Content-Length: 72
Host: localhost:8080

{"username":"newjunit","registrationAddToken":null,"recoveryToken":null}

Example response

HTTP/1.1 200 OK
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY
Content-Length: 648

{"status":"OK","registrationId":"Ey6LyiaXLwgM8wxeNIXnKQ==","publicKeyCredentialCreationOptions":{"rp":{"name":"localhost","id":"localhost","icon":{"empty":false,"present":true}},"user":{"name":"newjunit","displayName":"newjunit","id":"AAAAAAAAAAM","icon":{"empty":true,"present":false}},"challenge":"hZV-7roGRNnDzytShOxyDAvVTAHQTcVamfr2TYmDJZg","pubKeyCredParams":[{"alg":-7,"type":"public-key"},{"alg":-8,"type":"public-key"},{"alg":-257,"type":"public-key"}],"timeout":{"empty":true,"present":false},"excludeCredentials":{"empty":false,"present":true},"authenticatorSelection":{"empty":true,"present":false},"attestation":"none","extensions":{}}}

CURL request

$ curl 'http://localhost:8080/registration/start' -i -X POST \
    -H 'Content-Type: application/json;charset=UTF-8' \
    -H 'Accept: application/json' \
    -d '{"username":"newjunit","registrationAddToken":null,"recoveryToken":null}'

Registration finish

A POST request is used to fnish the Add User ceremony

Request structure

POST /registration/finish HTTP/1.1
Content-Type: application/json;charset=UTF-8
Accept: application/json
Content-Length: 855
Host: localhost:8080

{
  "registrationId": "KukKik86leDlveDwJvGZVA==",
  "credential": {
    "type": "public-key",
    "id": "ARgxyHfw5N83gRMl2M7vHhqkQmtHwDJ8QCciM4uWlyGivpTf00b8TIvy6BEpBAZVCA9J5w",
    "rawId": "ARgxyHfw5N83gRMl2M7vHhqkQmtHwDJ8QCciM4uWlyGivpTf00b8TIvy6BEpBAZVCA9J5w",
    "response": {
      "clientDataJSON": "eyJ0eXBlIjoid2ViYXV0aG4uY3JlYXRlIiwiY2hhbGxlbmdlIjoidTZvVFJqSDlpdk5HVnRORGRKZ2VTYWItWHNibEt6TGw1VHRKaTJaUmpCOCIsIm9yaWdpbiI6Imh0dHA6Ly9sb2NhbGhvc3Q6ODA4MCIsImNyb3NzT3JpZ2luIjpmYWxzZX0",
      "attestationObject": "o2NmbXRkbm9uZWdhdHRTdG10oGhhdXRoRGF0YVi4SZYN5YgOjGh0NBcPZHZgW4_krrmihjLHmVzzuoMdl2NFYQFsmK3OAAI1vMYKZIsLJfHwVQMANAEYMch38OTfN4ETJdjO7x4apEJrR8AyfEAnIjOLlpchor6U39NG_EyL8ugRKQQGVQgPSeelAQIDJiABIVggRrK9x1qVGusI8SJ2mhhtl0eY2wN4jJgGhUnoefCZSrgiWCBXhX1M2HIdIZDENOvj5NRZY_rR51ylCXJuvA6UivFpxQ"
    },
    "clientExtensionResults": {}
  }
}

Example response

HTTP/1.1 200 OK
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY
Content-Length: 44

{"recoveryToken":"l7NBeKAM1R4MwGlTIpA+Lg=="}

CURL request

$ curl 'http://localhost:8080/registration/finish' -i -X POST \
    -H 'Content-Type: application/json;charset=UTF-8' \
    -H 'Accept: application/json' \
    -d '{
  "registrationId": "KukKik86leDlveDwJvGZVA==",
  "credential": {
    "type": "public-key",
    "id": "ARgxyHfw5N83gRMl2M7vHhqkQmtHwDJ8QCciM4uWlyGivpTf00b8TIvy6BEpBAZVCA9J5w",
    "rawId": "ARgxyHfw5N83gRMl2M7vHhqkQmtHwDJ8QCciM4uWlyGivpTf00b8TIvy6BEpBAZVCA9J5w",
    "response": {
      "clientDataJSON": "eyJ0eXBlIjoid2ViYXV0aG4uY3JlYXRlIiwiY2hhbGxlbmdlIjoidTZvVFJqSDlpdk5HVnRORGRKZ2VTYWItWHNibEt6TGw1VHRKaTJaUmpCOCIsIm9yaWdpbiI6Imh0dHA6Ly9sb2NhbGhvc3Q6ODA4MCIsImNyb3NzT3JpZ2luIjpmYWxzZX0",
      "attestationObject": "o2NmbXRkbm9uZWdhdHRTdG10oGhhdXRoRGF0YVi4SZYN5YgOjGh0NBcPZHZgW4_krrmihjLHmVzzuoMdl2NFYQFsmK3OAAI1vMYKZIsLJfHwVQMANAEYMch38OTfN4ETJdjO7x4apEJrR8AyfEAnIjOLlpchor6U39NG_EyL8ugRKQQGVQgPSeelAQIDJiABIVggRrK9x1qVGusI8SJ2mhhtl0eY2wN4jJgGhUnoefCZSrgiWCBXhX1M2HIdIZDENOvj5NRZY_rR51ylCXJuvA6UivFpxQ"
    },
    "clientExtensionResults": {}
  }
}'

Authentication

Authentication start

A POST request is used to start the authentication ceremony

Request structure

POST /assertion/start HTTP/1.1
Content-Type: application/json;charset=UTF-8
Accept: application/json
Content-Length: 22
Host: localhost:8080

{ "username": "junit"}

Example response

HTTP/1.1 200 OK
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY
Content-Length: 333

{"assertionId":"FTE9ue5Wvl+IcN2eON+i5A==","publicKeyCredentialRequestOptions":{"challenge":"TBYbGa9fGTv03Ad29-T8ETEfnKRmNeSFcq1hz1qYRyU","timeout":{"empty":true,"present":false},"rpId":"localhost","allowCredentials":{"empty":false,"present":true},"userVerification":"preferred","extensions":{"appid":{"empty":true,"present":false}}}}

CURL request

$ curl 'http://localhost:8080/assertion/start' -i -X POST \
    -H 'Content-Type: application/json;charset=UTF-8' \
    -H 'Accept: application/json' \
    -d '{ "username": "junit"}'

Authentication finish

A POST request is used to finish the authentication ceremony

Request structure

POST /assertion/finish HTTP/1.1
Content-Type: application/json;charset=UTF-8
Accept: application/json
Content-Length: 766
Host: localhost:8080

{
  "assertionId": "bWnC7+6A/fUcwjl048iPOQ==",
  "credential": {
    "type": "public-key",
    "id": "ARgxyHfw5N83gRMl2M7vHhqkQmtHwDJ8QCciM4uWlyGivpTf00b8TIvy6BEpBAZVCA9J5w",
    "rawId": "ARgxyHfw5N83gRMl2M7vHhqkQmtHwDJ8QCciM4uWlyGivpTf00b8TIvy6BEpBAZVCA9J5w",
    "response": {
      "clientDataJSON": "eyJ0eXBlIjoid2ViYXV0aG4uZ2V0IiwiY2hhbGxlbmdlIjoiVWVCWWtKdTRjdk5xeDZGRmk0cVNJTDhLSURveDBwcXlNUzlXNmJBYlRIOCIsIm9yaWdpbiI6Imh0dHA6Ly9sb2NhbGhvc3Q6ODA4MCIsImNyb3NzT3JpZ2luIjpmYWxzZX0",
      "authenticatorData": "SZYN5YgOjGh0NBcPZHZgW4_krrmihjLHmVzzuoMdl2MFYQFsow",
      "signature": "MEUCIFnff70nAto5eJTwyVHYgoi_E3013MOnbUVHJWIfaWbWAiEA9tw1WfZjTl1LOx3JF4-HQVPDhvVNVpRMXmtR2BN3m9I",
      "userHandle": "AAAAAAAAAAE"
    },
    "clientExtensionResults": {}
  }
}

Example response

HTTP/1.1 200 OK
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY
Content-Length: 20

{"username":"junit"}

CURL request

$ curl 'http://localhost:8080/assertion/finish' -i -X POST \
    -H 'Content-Type: application/json;charset=UTF-8' \
    -H 'Accept: application/json' \
    -d '{
  "assertionId": "bWnC7+6A/fUcwjl048iPOQ==",
  "credential": {
    "type": "public-key",
    "id": "ARgxyHfw5N83gRMl2M7vHhqkQmtHwDJ8QCciM4uWlyGivpTf00b8TIvy6BEpBAZVCA9J5w",
    "rawId": "ARgxyHfw5N83gRMl2M7vHhqkQmtHwDJ8QCciM4uWlyGivpTf00b8TIvy6BEpBAZVCA9J5w",
    "response": {
      "clientDataJSON": "eyJ0eXBlIjoid2ViYXV0aG4uZ2V0IiwiY2hhbGxlbmdlIjoiVWVCWWtKdTRjdk5xeDZGRmk0cVNJTDhLSURveDBwcXlNUzlXNmJBYlRIOCIsIm9yaWdpbiI6Imh0dHA6Ly9sb2NhbGhvc3Q6ODA4MCIsImNyb3NzT3JpZ2luIjpmYWxzZX0",
      "authenticatorData": "SZYN5YgOjGh0NBcPZHZgW4_krrmihjLHmVzzuoMdl2MFYQFsow",
      "signature": "MEUCIFnff70nAto5eJTwyVHYgoi_E3013MOnbUVHJWIfaWbWAiEA9tw1WfZjTl1LOx3JF4-HQVPDhvVNVpRMXmtR2BN3m9I",
      "userHandle": "AAAAAAAAAAE"
    },
    "clientExtensionResults": {}
  }
}
'

Recovery

Recovery start

A POST request is used to start the recovery ceremony

Request structure

POST /registration/start HTTP/1.1
Content-Type: application/json;charset=UTF-8
Accept: application/json
Content-Length: 76
Host: localhost:8080

{"username":null,"registrationAddToken":null,"recoveryToken":"dG9rZW4tMTIz"}

Example response

HTTP/1.1 200 OK
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY
Content-Length: 642

{"status":"OK","registrationId":"W08vAOAX8iaiL4SLGN7RYg==","publicKeyCredentialCreationOptions":{"rp":{"name":"localhost","id":"localhost","icon":{"empty":false,"present":true}},"user":{"name":"junit","displayName":"junit","id":"AAAAAAAAAAE","icon":{"empty":true,"present":false}},"challenge":"mHGwnrzee8oNypfwV-EYqQ-UWkYrAes4W3RdH2bFjsQ","pubKeyCredParams":[{"alg":-7,"type":"public-key"},{"alg":-8,"type":"public-key"},{"alg":-257,"type":"public-key"}],"timeout":{"empty":true,"present":false},"excludeCredentials":{"empty":false,"present":true},"authenticatorSelection":{"empty":true,"present":false},"attestation":"none","extensions":{}}}

CURL request

$ curl 'http://localhost:8080/registration/start' -i -X POST \
    -H 'Content-Type: application/json;charset=UTF-8' \
    -H 'Accept: application/json' \
    -d '{"username":null,"registrationAddToken":null,"recoveryToken":"dG9rZW4tMTIz"}'

Add device

Generate registrationAddToken

A POST request is used to start the add device ceremony. For a given authenticated user, a new registration add token is created and valid for 10 minutes

Request structure

GET /registration/add HTTP/1.1
Content-Type: application/json;charset=UTF-8
Accept: application/json
Host: localhost:8080

Example response

HTTP/1.1 200 OK
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY
Content-Length: 51

{"registrationAddToken":"N/1N94jlP6KuIyTFAkdN8Q=="}

CURL request

$ curl 'http://localhost:8080/registration/add' -i -X GET \
    -H 'Content-Type: application/json;charset=UTF-8' \
    -H 'Accept: application/json'

Add device

On another device, a POST request is used to finish the add device ceremony. Given the registrationAddToken is valid, the new credentials are linked to the existing user.

Request structure

POST /registration/start HTTP/1.1
Content-Type: application/json;charset=UTF-8
Accept: application/json
Content-Length: 76
Host: localhost:8080

{"username":null,"registrationAddToken":"dG9rZW4tMTIz","recoveryToken":null}

Example response

HTTP/1.1 200 OK
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY
Content-Length: 642

{"status":"OK","registrationId":"t07B2lBX1voht8Gc9BdrBw==","publicKeyCredentialCreationOptions":{"rp":{"name":"localhost","id":"localhost","icon":{"empty":false,"present":true}},"user":{"name":"junit","displayName":"junit","id":"AAAAAAAAAAI","icon":{"empty":true,"present":false}},"challenge":"KY8E1H8YZfb954upHyD1uYB__S9xCj8N6HF0IGI9mBM","pubKeyCredParams":[{"alg":-7,"type":"public-key"},{"alg":-8,"type":"public-key"},{"alg":-257,"type":"public-key"}],"timeout":{"empty":true,"present":false},"excludeCredentials":{"empty":false,"present":true},"authenticatorSelection":{"empty":true,"present":false},"attestation":"none","extensions":{}}}

CURL request

$ curl 'http://localhost:8080/registration/start' -i -X POST \
    -H 'Content-Type: application/json;charset=UTF-8' \
    -H 'Accept: application/json' \
    -d '{"username":null,"registrationAddToken":"dG9rZW4tMTIz","recoveryToken":null}'