REST API
Last updated
Last updated
See more context here:
API requests are signed using a client credential (a private key) rather than using bearer tokens. This provides strong authentication and non-repudiation through the stack -- it proves where the request originated and eliminates the possibility of forged requests by the service operator (e.g. Narval).
Requests to the Vault require 2 authorization headers
GNAP Authorization header
Contains the AccessToken returned from the Authorization Request
header format: Authorization: GNAP access_token
Proof of possession of the credential the access token was issued to
The AccessToken is bound to the credential that initiated the request, so you must prove you hold that credential by signing the HTTP request and including the signature as a detached-jws
header format: Detached-jws: jws
To create the Detached JWS signature for your HTTP request, follow these steps
The Typescript ArmorySDK has functions to do this transparently for you
For more information, see GNAP RFC
Build the JWS Header
Take the accessToken returned from the Authorization Request, get the sha256 hash, then base64url encode it. This is the ath
value.
Canonicalize the header (ensure we have the same order) according to RFC8785 See Typescript implementation here
Check if the input is a number and handle special cases for NaN and Infinity.
If the input is null or not an object, convert it to a JSON string.
If the object has a toJSON method, canonicalize the result of this method.
If the input is an array, iterate through its elements, convert undefined or symbols to null, and canonicalize each element.
If the input is an object, sort its keys, filter out undefined and symbols, and canonicalize each key-value pair.
Return the canonicalized string representation of the array or object.
Encode the Header with base64url
Canonicalize the http request body (the entire http request body) with above steps
Hash the request body with SHA256 (if no body, use an empty payload)
Encode the body hash with base64url -- this is your JWS payload.
Sign the JWS
Sign ${encodedHeader}.${encodedPayload}
Use the key and algorithm referenced in the header above
Note: breaking from JWS spec, we support an EIP191 signature here, although the result should still be base64url encoded
Complete the JWS ${encodedHeader}.${encodedPayload}.${signature}
See our Typescript implementation of the full process here
Authorization Requests to the Armory are authenticated with a signature from a client credential.
This signature is presented as a JWT.
The payload is formatted as follows
Note: this is not the entire body, just the request
field.
Build the JWT header
Sign the JWT
Base64Url encode the canonical header
Base64Url encode the canonical payload
Sign ${encodedHeader}.${encodedPayload}
using the key & algorithm referenced.
As with jwsd, you can use an EIP191 signature and encode the result with base64url
Complete the JWS ${encodedHeader}.${encodedPayload}.${signature}
This value goes into the authentication
field of the AuthorizationRequest (or the approvals
field if you're signing an additional approval.
Take the request
field of the /authorization-request
body. . Hex encode the sha256 hash of the canonical request field, and include a 0x
prefix on the hex string.