Try   HackMD

Coordinator REST API

Design Decisions

Before specifying the API we lay discussion for some of the important design decisions that were made.

Why do we need a REST API?

At a high level, we have many participants who want to modify an object. The object needs to be modified one after another, so we need an entity who can sequence the participants and save their contributions. This is the main job of coordinator.

Abstracting away the details of the setup

It turns out that we can abstract away the details of the trusted setup. This is an advantageous approach because the cryptography that the coordinator uses from the trusted setup can be audited as a separate module.

To do this, we note that the coordinator is solely checking if state transitions are correct. The participants give the coordinator a state which they claim can be transitioned from the state that the coordinator hold along with a witness attesting to this transition.

Using this, we will remove terminology relating to the trusted setup.

Sessions Vs JSON Web Tokens(JWT) for Authorisation

There are many controversial takes around using JWT's for stateful processes. Many approaches were considered with JWT's however the fact that you cannot immediately revoke a JWT token is undesirable for our usecase. For example, when a participant has finished contributing, we would like them to not have access to the endpoint for contribution. With JWT tokens, there is a window of time where the contributor has finished contributing and the token has not expired that we must account for. We avoid these edge cases by using sessions for authorisation.

Note: We still use JWTs, just not for Authorisation of endpoints.

Lobby Style Synchronisation

The queue approach is used almost exclusively by ceremonies where the participants are not arbitrary. The lobby approach, to the writers knowledge has only been used in zk-party, that is to say, we are not completely re-inventing the wheel.

Analysing the differences between these two approaches is out of scope for this document, so we only consider the effect that the lobby approach has on the design of the REST API.

Summary of Lobby Approach

  • Define a maximum lobby size.
  • Users will attempt to sign in. If the addition of this user, will mean that the maximum lobby size is exceeded, then the user will not be able to sign in.
  • Once a user has signed in, they are in the lobby.
  • Users will periodically request to be given permission to modify the current state. This is known as reserving the contribution spot.
  • If users do not periodically request permission to reserve the contribution spot, they will be seen as offline and removed from the lobby.
  • Once a user is granted permission, they will be removed from the lobby and given a fixed amount of time to modify the current state. They will send a the new purported state along with a witness to the contributor, and the contributor will accept or reject their state transition.
  • If the state transition is accepted, then the coordinator will send the coordinator a receipt of contribution in the form of a signed JWT token.

Malicious Coordinator

There are two ways that the coordinator can be malicious:

  • Censoring certain participants based on their location or particular features.
  • Not including a particular contribution.

Censoring

If a participant believes they are being censored, they can obfuscate their IP address hiding their location, and use a new Ethereum address hiding their identity.

Many of these problems will be solved by ensuring that the coordinator software is deployed in a safe way such that an attacker cannot inject malicious censoring code and that the entities running the coordinator have something at stake, if they were to be caught censoring.

Missing Contribution

Once a coordinator tells a contributor that their contribution was successful, they send the contributor a signed receipt. If the coordinator then decides to not include the contribution, then a contributor can brandish the signed receipt as proof of contribution. The ramifications of this is out of scope for this document.

If the coordinator decides to not include valid contributions, then a contributor can simply try again.

We can also solve this problem on a social level, given that a handful of people may have felt like they were being censored or that their contribution was unfairly rejected, then we could extend the ceremony for these special ny for these special cases.ny for these special

Constants

  • MAX_LOBBY_SIZE : This is the maximum amount of participants that will be allowed in the lobby
  • COMPUTE_DEADLINE: This is the maximum amount of time that a participant has to compute a state transition.
  • CLIENT_SECRET : This is the OAuth secret that only the OAuth application and the authorisation server knows.
  • CLIENT_ID : This is the OAuth ID for the application that will be granted access to a users profile.
  • JWT_SECRET : This is the secret that will be used to allow the coordinator to sign JWT tokens. This should not change for the lifetime of the coordinator.
  • JWT_PUBLIC_KEY : This is the public key that the participants will use to verify that a JWT token was indeed signed by the coordinator.
  • HISTORY_RECEIPTS_COUNT : This is the number of recent receipts that the coordinator will send to clients that ask for a status on the ceremony.

CLIENT_SECRET must not be leaked. Do not store it as a constant.
JWT_SECRET must not be leaked. Do not store it as a constant.

Authorisation

Authorisation is done via OAuth. In particular, we use the Authorisation code flow.
Given that the coordinator can store theCLIENT_SECRET, Authorisation code flow + PKCE is not needed.

For authenticated endpoints, Bearer authorisation is used, where the Bearer token is the session identifier.

METHOD: GET

Request Parameters

Parameter Value Mandatory Description

Response Parameters

Response Type: Application/json

Parameter Value Mandatory Description
auth_url A string representing the OAuth application url yes Users will use this to sign into Github/Ethereum with and will be redirected to an allowed list of redirect_uri's

Discussion

Participants will grant read access to a particular OAuth application that the coordinator owns. The coordinator can then use the OAuth application to read the user's data.

Endpoint : /auth/authorised

METHOD: GET

Request Parameters

Parameter Value Mandatory Description
code Authorisation code yes Authorisation code nonce that the authorisation server gave to the client
state CSRF token yes Same as the value given in the auth_url

Response Parameters

Response Type: Application/json

Parameter Value Mandatory Description
id_token string representing a serialised id token in JWT format yes Resulting id token created from reading the users information from the authorisation server
session_id random string yes A random string that the server uses to identify the user

If a user logs in twice with the same social login, they will receive the same session identifier.

Id Token

Field Description
sub (subject) This is a unique and canonical string describing the user and the provider
nickname This is the display name associated with a social account
provider This is the social provider with whom we authenticated the user with
exp This the expiry time of the Id Token

Example : Github

  • sub: Github | 37423678
  • nickname : kevaundray
  • provider : Github

The expiry field is not needed, however some JWT libraries will return an error if it is not present.

Lobby

When a user successful authorises themselves, they are automatically placed into the lobby.

They will periodically attempt to join the contribution slot.

Endpoint : /slot/join

METHOD: POST

Request Parameters

Parameter Value Mandatory Description
session_id Session Identifier string yes Session Id that was given in /auth/authorised request

Response Parameters

Response Type: Application/json

Parameter Value Mandatory Description
success A space separated string no The presence of this parameter indicates that the user can now contribute

Contribute

Endpoint : /contribute

METHOD: POST

Request Parameters

Parameter Value Mandatory Description
session_id Session Identifier string yes Session Id that was given in /auth/authorised request
state JSON object representing the new state yes This is the state that the contributor wishes the coordinator to transition to
witness JSON object representing the witness for the state transition yes In order for the contributor to accept this new state, a witness must be supplied to show that the state transition from the state that the coordinator holds to the state in this payload, is valid

Response Parameters

Response Type: Application/json

Parameter Value Mandatory Description
receipt A string representing an encoded JWT token yes Once a contributor has contributed, they are given a JWT token that acts as a receipt

Receipt

Field Description
id_token The ID token that a contributor was given when they authenticated with the coordinator
witness Witness that was used in this participants contribution that led to the coordinator accepting the state transition

Info

Endpoint : /info/status

METHOD: GET

Request Parameters

Parameter Value Mandatory Description

Response Parameters

Response Type: Application/json

Parameter Value Mandatory Description
lobby_size An integer yes An integer describing how many participants are in the lobby
num_contributions An integer yes An integer describing how many contributions have been successful since the start of the ceremony
receipts A vector of encoded JWT receipt strings yes A list of the recent HISTORY_RECEIPTS_COUNT number of receipts

Endpoint : /info/current_state

METHOD: GET

Request Parameters

Parameter Value Mandatory Description

Response Parameters

Response Type: Application/json

Parameter Value Mandatory Description
state A JSON encoded object yes A JSON encoded object holding the current program state

Error Variants

For each endpoint, we list the failure modes (any response that does not return a 200 status code).

All errors are returned in the following JSON format:

{
    "error" : "message"
}

Note: that some errors arise from the user performing an invalid action like calling an authorised endpoint with no authorisation token. While others can arise from a user trying to enter the contribution slot. If a client wants to discern between the two, they should look at the HTTP status code sent along with the json payload.

Authorisation

Endpoint : /auth/request_link

  • Full Lobby

Reason: When a user requests a sign in link, we check if this user will exceed the MAX_LOBBY_SIZE count.

HTTP STATUS CODE: SERVICE_UNAVAILABLE (503)

{
    "error" : "lobby is full"
}

Endpoint : /auth/authorised

  • Invalid CSRF

Reason: It is standard to include a CSRF token when giving out an OAuth link, if the CSRF token that was sent out with the link, does not match the CSRF token received, this error is returned.

HTTP STATUS CODE: BAD_REQUEST (400)

{
    "error": "invalid csrf token"
}
  • Invalid Authorisation code

Reason: When exchanging the authorisation code for an access token, in the OAuth flow, one can be sent an invalid auth code.

HTTP STATUS CODE: BAD_REQUEST (400)

{
    "error": "invalid authorisation code"
}
  • Could not fetch user data

Reason: Given access token for a users profile, this error is returned if one fails to fetch the user's data from the authorisation server.

HTTP STATUS CODE: INTERNAL_SERVER_ERROR (500)

{
    "error": "could not fetch user data from auth server"
}
  • Could not extract user data

Reason: Once one has fetched the user's data, we must extract the necessary fields that we need from their profile. This error is returned in that case. This can happen due to a change in authorisation server's API.

HTTP STATUS CODE: INTERNAL_SERVER_ERROR (500)

{
    "error": "could not fetch user data from auth server"
}
  • User already contributed

Reason: Given that the OAuth code flow was successful, before adding a user to the lobby, we check if the user has already contributed. This is possible since a given social provider will have a unique string to identify each user.

HTTP STATUS CODE: BAD_REQUEST (400)

{
    "error": "user has already contributed"
}
  • Unknown Social Id Provider

Reason: When a user is authenticated, they are authenticated using Github/Ethereum. The coordinator checks whether this is the case.

HTTP STATUS CODE: BAD_REQUEST (400)

{
    "error": "unknown identity provider"
}
  • Invalid JWT Token Creation

Reason: The coordinator serialises and signs the Identity token that they wish to send to the contributor. This error is returned if the process did not successfully complete.

HTTP STATUS CODE: INTERNAL_SERVER_ERROR (500)

{
    "error": "token creation error"
}

Lobby

Endpoint : /slot/join

  • Unknown Session Identifier

Reason: This is an authenticated endpoint; users must supply their session id in the Authorisation header. If this session id is invalid, then this error is returned.

HTTP STATUS CODE: BAD_REQUEST (400)

{
    "error": "unknown session id"
}
  • Slot is Full

Reason: Users will continuously attempt to reserve the slot that gives them a right to contribute. If they are not successful, this error is returned.

HTTP STATUS CODE: SERVICE_UNAVAILABLE (503)

{
    "error": "slot is full"
}

Contribute

Endpoint : /contribute

  • Participation slot empty

Reason: If the participation slot is empty, then no-one is allowed to contribute. A user must first call /slot/join to reserve the spot.

HTTP STATUS CODE: BAD_REQUEST (400)

{
    "error" : "the spot to participate is empty"
}
  • Not Users Turn

Reason: This error occurs when a participant calls /contribute and it is not their turn to participate.

HTTP STATUS CODE: BAD_REQUEST (400)

{
    "error" : "not your turn to participate"
}
  • Invalid Contribution

Reason: This error occurs when the state transition function returns false. Given the current state, the new state and the witness.

HTTP STATUS CODE: BAD_REQUEST (400)

{
    "error" : "contribution invalid"
}
  • Invalid JWT Token Creation

Reason: The coordinator serialises and signs the Receipt token that they wish to send to the contributor. This error is returned if the process did not successfully complete.

HTTP STATUS CODE: INTERNAL_SERVER_ERROR (500)

{
    "error": "token creation error"
}