Client keys
All client requests in Open Payments are signed using a unique key that identifies the client to the authorization and resource servers. All requests, except for new grant requests, also carry an access token that is bound to the key.
Key registry
A key registry is a list of keys, generated and stored by the client, for when the client requires access to protected Open Payment resources. Since grant requests are completed over multiple signed HTTP requests, it’s important for the client to provide a way to consistently identify itself across these requests to the authorization server. The key registry allows the authorization server to verify that the client is who it says it is.
Each client is represented by a wallet address. A client’s key registry is publicly accessible through its wallet address via a jwks.json
endpoint. An authorization server can retrieve the client’s key registry by accessing WALLET_ADDRESS/jwks.json
.
https://wallet.example.com/alice/jwks.json
Registry structure
The key registry must expose public keys in the form of JSON Web Key Sets (JWKS). The keys must be generated using the Ed25519
algorithm and the resultant JWKS document must contain the following fields and values.
{ alg: 'EdDSA', kty: 'OKP', crv: 'Ed25519'}
Additionally, it must contain the x
and kid
(key ID) fields for the specific client to identify itself in a signature.
{ "keys": [ { "kid": "3724c845-829d-425a-9a0d-194d6f12c336", "x": "_Eg6UcC8G-O4TY2cxGnZyG_lMn0aWF1rVV-Bqn9NmhE", "alg": "EdDSA", "kty": "OKP", "crv": "Ed25519" } ]}
Key generation
Before a client can request a grant for the first time, it must:
- Generate an asymmetric key pair. Keys must be generated using the ed25519 algorithm.
- Add the public key to its key registry.
- Store the private key. The private key is used to sign the payload described in the key proofing method section below.
Client requests
Since client requests are completed over multiple signed HTTP requests, it’s important for a client to provide a way to consistently identify itself across these requests. As such, clients must include the following when making requests:
- Headers
- A
Signature-Input
header that includes thekeyId
associated with the client’s key pair. This header is a comma-separated list of headers that map to values in the data that was signed. - A
signature
header generated based on theSignature-Input
, using theEdDSA
signing algorithm
- A
- Body
- A
client
property containing the client’s wallet address
- A
Securing client requests follows a profile of what’s defined in the GNAP specification.
Grant requests
Upon receiving a signed grant request, the authorization server obtains the client’s domain from the client
property. The authorization server binds the domain to the grant in order to use the domain to acquire the key set for subsequent grant requests.
The authorization server then acquires the client’s key registry by making a GET
request to the client’s JWKS endpoint at WALLET_ADDRESS/jwks.json
. When the authorization server locates the public key containing the keyId
included in the request’s Signature-Input
header, the authorization server uses the key to decrypt and validate the request’s signature. This binds the client to the grant and allows the authorization server to continue with the grant request.
Key proofing method
HTTP message signatures
Open Payments uses the HTTP message signatures (httpsig
) key proofing method.
The httpsig
proofing method must be declared as part of the key material when directly using a key to request a grant. The key material below is for illustrative purposes. In Open Payments, it’s expected that the wallet address be used in the grant request.
"key": { "proof": "httpsig", "jwk": { "kid": "3724c845-829d-425a-9a0d-194d6f12c336", "x": "_Eg6UcC8G-O4TY2cxGnZyG_lMn0aWF1rVV-Bqn9NmhE", "alg": "EdDSA", "kty": "OKP", "crv": "Ed25519" }}
When using httpsig
, the signer (the client) creates an HTTP message signature. Open Payments clients typically secure their requests to servers by presenting an access token and proof of a key it possesses. The exception is for calls to an authorization server to initiate a grant. In this case, a key proof is used with no access token and is a non-authorized signed request.
See the HTTP message signatures page for more information specific to Open Payments. Additional information is found in the specification for HTTP message signatures.
Sequence diagram
This diagram shows the sequence of calls needed between a client and the servers on the sender’s side to obtain an interactive grant for creating an outgoing-payment
resource.
sequenceDiagram participant C as Client participant AS as Authorization server participant RS as Resource server C->>C: 1.) Generates public/private key pair,
adds the public key to its key registry C->RS: Public key uploaded/accessible at the RS C->>AS: 2.) Requests an interactive outgoing-payment
grant (POST /), signs request with private key AS->>AS: 3.) Pulls keyId from grant request's signature-input
header, gets client's domain from request's body AS->>RS: 4.) Requests public keys from client's JWKS endpoint
GET {client_domain/jwks.json} RS-->>AS: 5.) 200 domain found,
returns public key AS->>AS: 6.) Uses public key to validate the signature in the client's
original request, binds client's domain to the grant AS-->>C: 7.) 200 OK note over AS: Explicit consent is collected from the client's user, facilitated by the client, authorization server, and IdP (not shown) C->>AS: 8.) Makes grant continuation request
(POST /continue) signed with private key AS->>AS: 9.) Pulls the keyId from the grant request's
signature-input header, gets client's domain
from the database entry for the grant AS->>RS: 10.) Requests public key bound to the domain from client's
JWKS endpoint GET {client_domain/jwks.json} RS-->>AS: 11.) 200 domain found,
returns public key AS->>AS: 12.) Finds the registry key with the matching
keyId, validates signature with key AS-->>C: 13.) 200 success,
access token issued,
grant continuation request complete