Authenticity API → Authenticity JWT
The VivoKey Authenticity API enables applications and services to check the authenticity of components and products containing VivoKey technology using strong standards based cryptographic proofs over NFC (contactless near field communication). Once the VivoKey NFC chip is scanned, a cryptographic challenge is obtained from VivoKey servers. That challenge is passed to the NFC chip and a response is generated. The response is sent back to VivoKey for validation.
Once validated, a signed Json Web Token or JWT called an "authenticity token" is issued. The typical format of a JWT is three Base64-URL strings separated by dots that can be easily passed in HTML and HTTP environments, while being more compact when compared to XML-based standards such as SAML.
Authenticity JWT explained
The strength of a cryptographically signed Json Web Token (JWT) is that once issued, the contents can be trusted to be authentic and unaltered. The authenticity of the JWT can be validated by any server or service without needing to make any additional API calls by checking the JWT signature against a public key published by the issuer (VivoKey). By validating the JWT signature you can be assured of two things; the JWT was issued by VivoKey, and the contents has not been altered.
A typical JWT is encoded as three Base64-URL strings separated by dots. The first section is called the header, the middle section is the payload, and the last section is the signature. Here is an example encoded authenticity token returned by the /session API endpoint.
You can view the authenticity token at jwt.io. As you can see, the decoded JWT has the following JSON structure;
The header contains typ, alg, and kid which mean, respectfully, type of token, signature algorithm used, and key ID of the private key used to sign with. The only real important value in the header is the algorithm used for signing the JWT as this will need to be the algorithm used validate it.
The payload section contains the following "claims".
- sub (subscriber) is the fully validated and authentic chip ID that can be stored in local service databases and used as a reliable secure identifier for this specific chip in this specific product. The same chip ID is returned for any and all API keys *associated with your developer account email.
- iat (issued at) is a Unix timestamp representing the number of seconds which have passed since Jan 1, 1970. The iat timestamp represents the UTC date and time that the token was created.
- exp (expiration) is a Unix timestamp representing the time the token expires, which is 30 seconds from the time the token was issued (iat). The token must be considered expired if the current time has surpassed the exp time.
- cld (client data) is optionally included if cld data (up to 1024 bytes) was provided to the /session endpoint.
- atp (authentication type) is the mechanism used to validate authenticity of the chip. Possible values are cmac for counter based signature validations, tam for tag auth mechanism, or mau for mutual authentication. It is not generally important to know which mechanism was used, however CMAC authenticated tokens cannot be renewed and are generally considered to be low security compared to other forms of authentication types. The atp claim can be used to help establish a level of trust consumers wish to grant the token.
- type (chip type) means the actual type of chip inside the device being validated for authenticity. This is not necessarily all that useful outside of VivoKey internal services, but it's passed as part of the token so that VivoKey services need only consume the token itself, and not need to perform internal lookups or calls to determine authenticity of the contents.
- product (product code) is another simple identifier to easily differentiate which type of product a particular chip type is in, be it a wearable, implant, or otherwise. (1) Spark 1, (2) Spark 2, (3) Demo Card, (4) Apex, (5) Licensed Signature.
- iss (issuer) is a standard registered claim which indicates who or what issued the token.
- jti (jwt id) is a random string unique identifier for this exact token. The intent is to easily enable one time use of the token and guard against replay attacks during the time between iat and exp.
*It is important to understand that the chip ID returned in the sub claim of the authenticity token is a hash based on a combination of values including internal VivoKey chip identifier, internal VivoKey developer account identifier (associated with the email address the API key was sent to), and some additional data elements. This results in a chip ID value that is the same for every API key associated with your developer email address. However, to help improve privacy, API keys for different developers will return different chip IDs for the same chip. This makes it more difficult for services to share databases and identify the same product / user / person across multiple services without their consent.
The signature section is a hash signature of the header and payload sections, encrypted using a private key secured inside VivoKey servers. When used with the public key given below, you can validate the signature of the authenticity token. In turn, this validates that the contents of the token have not been altered, such as the chip value or exp timestamp.
Validating authenticity token signatures
After validating the authenticity of a VivoKey chip or product using our API, what happens if you want to communicate that information between servers, or mobile app and backend service? How does your backend know it's receiving legitimate data? How does it know it can even trust the authenticity JWT itself? It might be easy to assume you can trust it when you just received it from our API endpoint, but when you need to pass that information to a backend server to perform more functions, that chain of trust is lost. How does that server know someone isn't just passing bogus data into your server or service endpoint? The answer is JWT signature validation.
By using a JWT based authenticity token, we solve the trust problem by containing all of the critical information inside the JWT, including expiration time (after which the token is considered to be invalid). All of that data is then hashed and signed using the private key of a VivoKey public private key pair, and the signature is suffixed as part of the JWT structure. That means you can simply pass the complete authenticity token to your server, and it can validate the signature using a locally cached copy of the VivoKey public key to confirm the contents is valid and unaltered, without having to check with VivoKey APIs to ensure the token is valid.
The Json Web Key Set (JWKS)
The industry standard way to publish public keys for signature verification is by using a Json Web Key Set (JWKS). It is a array of one or more json keys, each containing cryptographic keys used to verify JWT signatures. The JWKS may contain multiple keys, so each key in the JWKS has a Key ID (kid), which is used to match the correct key with the kid value in the JWT header. Our jwks.json file is published using the standard "well known" URL;
Employ jwks.json caching
Part of the point of signing a JWT is to ensure you don't have to make any calls to external servers for every single signature validation. Proper signature validation behavior is to keep a local copy of the jwks cached on your server and / or application. You should only be pulling down the jwks.json data on initial JWT signature validation, if the matching key ID for the JWT is not found in the cached jwks, or on a signature failure. In that case, pull down a fresh copy of the jwks and check again. You can also opt to refresh jwks.json periodically based on your own schedule.
JWT signature validation flow
Public key EC and PEM formats
Our authenticity JWTs are signed using the ES256 (EC) algorithm, so the public key inside the JWKS is formatted as elliptic curve points with x and y coordinates. However some JWT processing libraries require PEM format public keys. For your convenience we include a special element value inside called pem which contains the public key in PEM format.
Validate your tokens!
It is extremely important that you actually perform validation of the token signature and not ignore it in favor of focusing exclusively on the payload data. The exact process to do this will depend on which JWT library you use to parse the authenticity token. The rule of thumb in the cryptography industry is that you don't roll your own crypto. There are tons of JWT processing libraries for every kind of platform and language. Find a well supported one and use that to parse and validate authenticity tokens at every point along your application or service where the authenticity token is passed between systems or processes. This is especially important if your service has API endpoints accessible to the internet which anyone can take a stab at passing data to.
Unique token identification
There may be some situations where you want your external endpoint consuming an authenticity token one time only. This is generally used to protect against replay attacks during the period of time after iat and before exp. As long as you are honoring the exp claim and invalidating tokens after the exp time, you only have to store and compare unique jti values for the short period of time that authenticity tokens are valid.
Handling token aging
The value of a JWT is that it can be validated without doing anything other than a signature check, but that's only half of the trust mechanism. The other half is how you handle token aging. The signature verification process ensures the token;
- has been legitimately issued by VivoKey
- has not been altered by a 3rd party
However, if that's the only check being performed, then anyone with a copy of a valid signed token could supply it at anytime (replay attack) to your services or API endpoints. To ensure the token is minty fresh, you will have to decide how to handle token aging. In the payload, we supply two UTC timestamps; iat (issued at time) and exp (expiration time). The exp timestamp is 30 seconds after iat, so as far as VivoKey is concerned, tokens have a 30 second lifespan. VivoKey will not accept an expired token for any services processing or token renewal. However, you are free to decide how you want to handle token aging within your own systems.
Typically, you should be checking to see if current UTC timestamp > exp and if so, consider the token expired. If you decide that you want to trust the validity of a token for less or more time than 30 seconds, you are free to make your own calculation; expired after iat + N seconds. Just be aware that the longer a token's lifespan, the larger time window potential replay attacks have.
VivoKey will soon have a renewal endpoint for unexpired tokens. This endpoint will allow you to submit an unexpired token to be renewed, which will update the exp timestamp for another 30 seconds (UTC + 30s), but retain the original iat timestamp, then sign and issue the new JWT. This will allow you to determine the original token's issue timestamp while ensuring the token is still considered "fresh". The renewal process will be necessary to continue to use the authenticity token with VivoKey services beyond the initial 30 second token lifespan. Of course you can also establish and maintain your own client service sessions using this same method.