Validation Protocol Version 2.0

Introduction

All requests are HTTP GET requests. As such, all parameters must be properly URL encoded. In particular, some base64 characters (such as "+") in the value fields need to be escaped.

Each request sent to the server can be signed. To ensure that the server rejects any requests that have been tampered with, clients should sign each request they make to the server.

Each response sent by the server is signed. To verify that the response has not been tampered with, clients should verify the HMAC signature and must use HTTPS connections (and verify the server certificate).

Generating signatures

The protocol uses HMAC-SHA-1 signatures. The HMAC key to use is the client API key.

Generate the signature over the parameters in the message. Each message contains a set of key/value pairs, and the signature is always over the entire set (excluding the signature itself), and sorted in alphabetical order of the keys. More precisely, to generate a message signature do:

  • Alphabetically sort the set of key/value pairs by key order.

  • Construct a single line with each ordered key/value pair concatenated using &, and each key and value contatenated with =. Do not add any linebreaks. Do not add whitespace. For example: a=2&b=1&c=3.

  • Apply the HMAC-SHA-1 algorithm on the line as an octet string using the API key as key (remember to base64decode the API key obtained from Yubico).

  • Base 64 encode the resulting value according to RFC 4648, for example, t2ZMtKeValdA+H0jVpj3LIichn4=.

  • Append the value under key h to the message.

Verifying signatures

To verify a signature on a response message, follow the same procedure that was used to sign the response message and compare the signature in the response to the signature you generated. If the signature values are equal, the signature is correct. Make sure you remove the signature itself from the values you generate the signature over for verification. If the incoming message is

b=1&a=2&c=3&h=V5FkMYr9GCG9tQA9ihuuybWl99U=

make sure to remove h before verifying:

b=1&a=2&c=3

Don’t forget to sort the key/value pairs.

You can verify your signature implementation using the test vectors.

Verification

There is one call to verify YubiKey OTPs: verify.

The verify call lets you check whether an OTP is valid. Since the OTP itself contains identification information, all you have to do is to send the OTP.

To avoid cut’n'paste attacks, the client must verify that the "otp" in the response is the same as the "otp" supplied in the request.

Request

Construct an HTTP GET call to

https://api.yubico.com/wsapi/2.0/verify

with the following parameters (note that this request need not be signed):

parameter type required purpose

id

string

Yes

Specifies the requestor so that the end-point can retrieve correct shared secret for signing the response.

otp

string

Yes

The OTP from the YubiKey.

h

string

No

The optional HMAC-SHA1 signature for the request.

timestamp

string

No

Timestamp=1 requests timestamp and session counter information in the response

nonce

string

Yes

A 16 to 40 character long string with random unique data

sl

string

No

A value 0 to 100 indicating percentage of syncing required by client, or strings "fast" or "secure" to use server-configured values; if absent, let the server decide

timeout

integer

No

Number of seconds to wait for sync responses; if absent, let the server decide

An example request:

https://api.yubico.com/wsapi/2.0/verify?otp=vvvvvvcucrlcietctckflvnncdgckubflugerlnr&id=87&timeout=8&sl=50&nonce=askjdnkajsndjkasndkjsnad

And if you require additional information on timestamp and session counters:

https://api.yubico.com/wsapi/2.0/verify?id=87&otp=vvvvvvcucrlcietctckflvnncdgckubflugerlnr&timeout=8&sl=50&nonce=askjdnkajsndjkasndkjsnad&timestamp=1

If you are using the public YubiCloud service (api.yubico.com), you must use HTTP over TLS and you must use Server Name Indication. You should not hard-code the IP addresses that the DNS name resolves to, and you should not pin the TLS certificates that the service presents. You should sign your API requests and validate the response signatures as described above.

Response

If the verification server has successfully processed your request (even if the response is not a successful verification), it will return an HTTP status of 200 OK with a text/plain body.

If you get a 4xx or 5xx response you should retry your request a few times, as intermediate proxies and gateways may cause transient errors. If you are using a locally-hosted validation server on your own network, this may not be necessary.

The body consists of a number of parameter=value pairs, separated by CR LF.

For example:

h=4uvN1cIqh0vk6bnkO8ya48L2F5c=
t=2020-01-06T02:52:13Z0998
otp=cccccckdvvulgjvtkjdhtlrbjjctggdihuevikehtlil
nonce=ba336f7fdb9b8fec5d6d70313125d9985f6d295e
sl=20
status=OK

or

h=paOSl7f61trM4PPLnlFFLuR+z20=
t=2020-01-06T02:52:23Z0098
otp=cccccckdvvulgjvtkjdhtlrbjjctggdihuevikehtlil
nonce=ba336f7fdb9b8fec5d6d70313125d9985f6d295e
status=REPLAYED_REQUEST

The verification response tells you whether the OTP is valid. The response has the following values:

parameter type purpose

otp

string

The OTP from the YubiKey, from request

nonce

string

Random unique data, from request

h

string (base64)

Signature as described above.

t

time stamp

Timestamp in UTC

status

string

The status of the operation, see below

timestamp

string

YubiKey internal timestamp value when key was pressed

sessioncounter

string

YubiKey internal usage counter when key was pressed

sessionuse

string

YubiKey internal session usage counter when key was pressed

sl

integer

percentage of external validation server that replied successfully (0 to 100)

These are the possible "status" values in a verify response:

name meaning

OK

The OTP is valid.

BAD_OTP

The OTP is invalid format.

REPLAYED_OTP

The OTP has already been seen by the service.

BAD_SIGNATURE

The HMAC signature verification failed.

MISSING_PARAMETER

The request lacks a parameter.

NO_SUCH_CLIENT

The request id does not exist.

OPERATION_NOT_ALLOWED

The request id is not allowed to verify OTPs.

BACKEND_ERROR

Unexpected error in our server. Please contact us if you see this error.

NOT_ENOUGH_ANSWERS

Server could not get requested number of syncs during before timeout

REPLAYED_REQUEST

Server has seen the OTP/Nonce combination before

Changes since version 1.1

The verify URL has changed. In the request, the new required field "nonce" were added, and the new optional fields "sl" and "timeout" are added. In the response, the new fields "otp", "nonce", and "sl" are added. The status codes NOT_ENOUGH_ANSWERS and REPLAYED_REQUEST were added.

Since both the URL and required fields has changed, version 2.0 is not backwards compatible with version 1.1 or version 1.0. However, because version 2.0 use a different URL than version 1.x, the server may support both version 1.x and version 2.0 clients at the same time.