Skip to content
This repository has been archived by the owner on Dec 12, 2024. It is now read-only.

Commit

Permalink
Update readme to detail JWT token requirement for get exchanges endpo…
Browse files Browse the repository at this point in the history
…int auth (#216)

* adding authn and authz sections where missing. added authn and authz section for list exchanges to expand on JWT token required fields

* fixing readme links

* Apply suggestions from code review

Co-authored-by: Andres Uribe <[email protected]>

* Update specs/http-api/README.md

Co-authored-by: Andres Uribe <[email protected]>

* moving the auth wordings to the top of the readme

* referencing rfc6750 spec in describing jwt bearer token

---------

Co-authored-by: Andres Uribe <[email protected]>
  • Loading branch information
Jiyoon Koo and andresuribe87 authored Jan 16, 2024
1 parent 4540cec commit ef9d6c5
Showing 1 changed file with 137 additions and 57 deletions.
194 changes: 137 additions & 57 deletions specs/http-api/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,51 +14,63 @@ Version: Draft
- [Discoverability](#discoverability)
- [Example](#example)
- [Error Responses](#error-responses)
- [Error object](#error-object)
- [Example](#example-1)
- [Query Params](#query-params)
- [Pagination](#pagination)
- [Example](#example-1)
- [Example](#example-2)
- [Idempotency](#idempotency)
- [Protected Endpoints](#protected-endpoints)
- [Authentication](#authentication)
- [Token Generation](#token-generation)
- [Header](#header)
- [Claims Set](#claims-set)
- [Token Verification](#token-verification)
- [Offerings](#offerings)
- [List Offerings](#list-offerings)
- [Description](#description)
- [Endpoint](#endpoint)
- [Authentication](#authentication)
- [Authorization](#authorization)
- [Protected](#protected)
- [Query Params](#query-params-1)
- [Response](#response)
- [Exchanges](#exchanges)
- [Submit RFQ](#submit-rfq)
- [Description](#description-1)
- [Endpoint](#endpoint-1)
- [Authentication](#authentication-1)
- [Authorization](#authorization-1)
- [Protected](#protected-1)
- [Request Body](#request-body)
- [Response](#response-1)
- [Errors](#errors)
- [Get Quote](#get-quote)
- [Get Quote/Order/OrderStatus](#get-quoteorderorderstatus)
- [Description](#description-2)
- [Endpoint](#endpoint-2)
- [Protected](#protected-2)
- [Response](#response-2)
- [Response Body](#response-body)
- [Submit Order](#submit-order)
- [Description](#description-3)
- [Endpoint](#endpoint-3)
- [Protected](#protected-3)
- [Order Request Body](#order-request-body)
- [Response](#response-3)
- [Errors](#errors-1)
- [Submit Close](#submit-close)
- [Description](#description-1)
- [Description](#description-4)
- [Endpoint](#endpoint-4)
- [Protected](#protected-4)
- [Request Body](#request-body-1)
- [Response](#response-4)
- [Errors](#errors-2)
- [Get Exchange (DESCOPED)](#get-exchange-descoped)
- [Description](#description-2)
- [Authentication](#authentication-2)
- [Description](#description-5)
- [Endpoint](#endpoint-5)
- [Protected](#protected-5)
- [Query Params](#query-params-2)
- [Response](#response-5)
- [List Exchanges](#list-exchanges)
- [Description](#description-3)
- [Authentication](#authentication-3)
- [Description](#description-6)
- [Endpoint](#endpoint-6)
- [Protected](#protected-6)
- [Response](#response-6)
- [Query Params](#query-params-3)
- [References](#references)
Expand Down Expand Up @@ -94,24 +106,24 @@ If the serviceEndpoint is itself a DID, this did should resolve to a document an
* If present, the body of an error response will conform to the following:


| Field | Required (Y/N) | Description |
| ------------------ | -------------- | ------------------------- |
| `errors` | Y | List of `Error` objects |
| Field | Required (Y/N) | Description |
| -------- | -------------- | ----------------------- |
| `errors` | Y | List of `Error` objects |


## Error object
| Field | Required (Y/N) | Description |
| ------------------ | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `id` | N | A unique identifier for this particular occurrence of the problem. |
| `status` | N | The HTTP status code applicable to this problem, expressed as a string value. This SHOULD be provided. |
| `code` | N | An application-specific error code, expressed as a string value. |
| `title` | N | A short, human-readable summary of the problem that SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization. |
| `detail` | Y | A human-readable explanation specific to this occurrence of the problem. Like `title`, this field’s value can be localized. |
| `source` | N | An object containing references to the primary source of the error. It should include the `pointer`, `parameter`, or `header` members or be omitted. |
| `source.pointer` | N | A JSON Pointer to the value in the request document that caused the error. This MUST point to a value in the request document that exists; if it doesn’t, the client SHOULD simply ignore the pointer. |
| `source.parameter` | N | A string indicating which URI query parameter caused the error. |
| `source.header` | N | A string indicating the name of a single request header which caused the error. |
| `meta` | N | A meta object containing non-standard meta-information about the error. |
| `id` | N | A unique identifier for this particular occurrence of the problem. |
| `status` | N | The HTTP status code applicable to this problem, expressed as a string value. This SHOULD be provided. |
| `code` | N | An application-specific error code, expressed as a string value. |
| `title` | N | A short, human-readable summary of the problem that SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization. |
| `detail` | Y | A human-readable explanation specific to this occurrence of the problem. Like `title`, this field’s value can be localized. |
| `source` | N | An object containing references to the primary source of the error. It should include the `pointer`, `parameter`, or `header` members or be omitted. |
| `source.pointer` | N | A JSON Pointer to the value in the request document that caused the error. This MUST point to a value in the request document that exists; if it doesn’t, the client SHOULD simply ignore the pointer. |
| `source.parameter` | N | A string indicating which URI query parameter caused the error. |
| `source.header` | N | A string indicating the name of a single request header which caused the error. |
| `meta` | N | A meta object containing non-standard meta-information about the error. |

---

Expand Down Expand Up @@ -156,9 +168,62 @@ The IDs of individual tbDEX messages are used as idempotency keys

---

# Protected Endpoints

A **_protected endpoint_** is defined as one that requires the requester to be _authenticated_. These endpoints respond with resources specific to the authenticated DID e.g.
* Messages sent by or intended for the requester only
* Balances

> [!NOTE]
> Each individual endpoint section in this specification will include `Protected: true/false` to indicate whether it is protected
## Authentication

When accessing a protected endpoint, a tbdex http client MUST set the HTTP [Authorization Header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Authorization) in order to be authenticated.

The value of the header MUST use the Bearer Authentication Scheme as defined in [RFC 6750](https://datatracker.ietf.org/doc/html/rfc6750#section-2.1), and the access token MUST be a JWT.

### Token Generation

The bearer token is a [JSON Web Token (JWT)](https://datatracker.ietf.org/doc/html/rfc7519) generated by the requester. It must consist of JWT header and Claims Set containing the below fields, and signed using the verification method published as the authentication verification relationship in the requester's DID document.

#### Header

| Key | Description |
| -------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| [`typ`](https://datatracker.ietf.org/doc/html/rfc7519#section-5.1) | JWT. Setting `typ` to `JWT` as recommended by the JWT spec provides a means to disambiguate among different types of signatures and tokens. |
| [`kid`](https://datatracker.ietf.org/doc/html/rfc7515#section-4.1.4) | Fully qualified [VerificationMethod ID](https://www.w3.org/TR/did-core/#verification-methods). Used to locate the DID Document verification method utilized to verify the integrity of the JWT. |
| [`alg`](https://datatracker.ietf.org/doc/html/rfc7515#section-4.1.1) | Cryptographic algorithm used to compute the JWT signature. |


#### Claims Set

| Key | Description |
| -------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [`aud`](https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.3) | The intended PFI's DID. Incorporating the `aud` claim limits the risk to just one PFI in case a request token is compromised, thereby reducing the surface area for misuse. |
| [`iss`](https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.1) | The requester's DID. Included to be informative, though it is technically duplicative as the `kid` also includes the requester's DID. |
| [`exp`](https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.4) | Expiration timestamp. Limits the amount of time a compromised request token can be used. |
| [`iat`](https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.6) | Indicates when the JWT was created. Included to be informative. |
| [`jti`](https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.7) | Used as a nonce to prevent replay attacks. The specification text should include more detail on how to prevent these attacks. |

> [!NOTE]
> This bearer token is sufficient for authentication as it proves that the requester controls the private key associated to the DID that the requester is identifying as.

## Token Verification

The receiver of the token must evaluate it to ensure its validity. A bearer token is valid if these conditions are met:

- `exp` timestamp is not in the past
- `aud` is the DID of the receiving PFI's DID
- `kid` is resolved to be a valid DID whose DID Document verification method is used to verify the integrity of the JWT
- `jti` is not a nonce that was previously used by the same requester

---

# Offerings

The [`Offering`](../README.md#offering) resource is used to convey the currency pairs a PFI is _offering_. It includes information about payment methods and associated fees.
The [`Offering`](../protocol/README.md#offering) resource is used to convey the currency pairs a PFI is _offering_. It includes information about payment methods and associated fees.

## List Offerings

Expand All @@ -169,11 +234,8 @@ Used to fetch offerings from a PFI
### Endpoint
`GET /offerings`

### Authentication
No authentication required.

### Authorization
No authorization required. Offerings are publicly accessible
### Protected
False

### Query Params
| Param | Description |
Expand All @@ -198,17 +260,18 @@ An exchange is a series of linked tbDEX messages between Alice and a PFI for a s

## Submit RFQ

### Description
Submits an RFQ (Request For Quote). Alice is asking the PFI to provide a Quote so she can evaluate it.

### Endpoint
`POST /exchanges/:exchange_id/rfq`

### Authentication
Refer to [Signature Verification Section]() of the tbDEX spec
### Authorization
No Authorization required to submit an RFQ
### Protected
False

### Request Body
> [!IMPORTANT]
> See RFQ structure [here](../README.md#rfq-request-for-quote)
> See RFQ structure [here](../protocol/README.md#rfq-request-for-quote)
### Response
| Status | Body |
Expand All @@ -225,28 +288,43 @@ No Authorization required to submit an RFQ
| 409 | RFQ already exists |
| 409 | Exchange already exists |

## Get Quote
## Get Quote/Order/OrderStatus

### Description
Retrieve the desired tbdex message type given an exchangeId.

### Endpoint
`GET /exchanges/:exchange_id/?messageType=quote`

### Protected
True

### Response
| Status | Body |
| ------------------ | --------------------------------- |
| `200: OK` | `{ data: TbdexMessage<Quote>[] }` |
| `400: Bad Request` | `{ errors: Error[] }` |
| Status | Body |
| ------------------ | --------------------------------------------------- |
| `200: OK` | `{ data: TbdexMessage<Quote/Order/OrderStatus>[] }` |
| `400: Bad Request` | `{ errors: Error[] }` |

### Response Body
> [!IMPORTANT]
> See Quote structure [here](../README.md#quote)
> See Quote structure [here](../protocol/README.md#quote)
> See Order structure [here](../protocol/README.md#order)
> See OrderStatus structure [here](../protocol/README.md#orderstatus)
## Submit Order

### Description
Submits the Order. Alice wants to accept the Quote and execute the transaction.

### Endpoint
`POST /exchanges/:exchange_id/order`

### Protected
False

### Order Request Body
> [!IMPORTANT]
> See Order structure [here](../README.md#order)
> See Order structure [here](../protocol/README.md#order)

### Response
Expand All @@ -271,9 +349,12 @@ Closes the exchange. Indicates that Alice is no longer interested
### Endpoint
`POST /exchanges/:exchange_id/close`

### Protected
False

### Request Body
> [!IMPORTANT]
> See Close structure [here](../README.md#close)
> See Close structure [here](../protocol/README.md#close)

### Response
Expand All @@ -296,12 +377,11 @@ Closes the exchange. Indicates that Alice is no longer interested
### Description
Retrieves the messages specified by ID and messageType

### Authentication
Uses DID authn via Bearer token in header.

### Endpoint
`GET /exchanges/:id`

### Protected
True

### Query Params
| Param | Description |
Expand All @@ -323,29 +403,29 @@ Uses DID authn via Bearer token in header.
## List Exchanges

### Description
Returns an array of tbdex message arrays

### Authentication
Uses DID authn via Bearer token in header.
Returns an array of tbdex message arrays (a list of exchanges)

### Endpoint
`GET /exchanges`

### Protected
True

### Response
| Status | Body |
| ------------------ | -------------------------------------- |
| `200: OK. ` | `{ data: { TbdexMessage[][] } }` |
| `400: Bad Request` | `{ errors: Error[] }` |
| `404: Not Found` | N/A |
| `403: Forbidden` | N/A |
| Status | Body |
| ------------------ | -------------------------------- |
| `200: OK.` | `{ data: { TbdexMessage[][] } }` |
| `400: Bad Request` | `{ errors: Error[] }` |
| `404: Not Found` | N/A |
| `403: Forbidden` | N/A |

### Query Params

| Param | Description |
| ----- | ------------------------ |
| id | exchange id(s) to return |


---

# References
* JSON:API spec: https://jsonapi.org/format/

0 comments on commit ef9d6c5

Please sign in to comment.