Skip to content

Latest commit

 

History

History
691 lines (514 loc) · 30.7 KB

sep-0030.md

File metadata and controls

691 lines (514 loc) · 30.7 KB

Preamble

SEP: 0030
Title: Account Recovery: multi-party recovery of Stellar accounts
Author: Leigh McCulloch <@leighmcculloch>, Lindsay Lin <@capybaraz>
Track: Standard
Status: Draft
Discussion: https://groups.google.com/forum/#!topic/stellar-dev/SFr2dHBZlsY
Created: 2019-12-20
Updated: 2021-05-04
Version: 0.8.1

Summary

This protocol defines an API that enables an individual (e.g., a user or wallet) to regain access to a Stellar account that it owns after the individual has lost its private key without providing any third party control of the account. Using this protocol, the user or wallet will preregister the account and a phone number, email, or other form of authentication with one or more servers implementing the protocol and add those servers as signers of the account. If two or more servers are used with appropriate signer configuration no individual server will have control of the account, but collectively, they may help the individual recover access to the account. The protocol also enables individuals to pass control of a Stellar account to another individual.

Dependencies

Implementers and clients of this protocol must also implement SEP-10.

Motivation

The ability for users to gain access to a Stellar account using credentials other than the account keys is a critical feature of wallets that support the following use cases for a user:

  1. Recover – Recover access to Stellar accounts for which they may have lost keys.
  2. Share – Gain access to Stellar accounts that another user intends to share with them.

Solutions exist for wallets to store keys for users and to allow users to retrieve those keys, such as the keystore service, but those solutions usually prevent the server from controlling the account by requiring the user to remember an encryption password that, if forgotten, means permanent loss of the account. Those solutions also don't typically support sharing accounts.

The user experience is improved if gaining access to a Stellar account does not require remembering a password.

Abstract

This protocol defines an API allowing a client to register an account with a server, and later ask the server to sign transactions for the account.

The registration flow is as follows:

  • The client uses SEP-10 to get a JWT proving high threshold control of an account.
  • The client, authenticated as the account, registers with the server, providing:
    • One or more identities of individuals that can request the server sign transactions for the account, and for each identity:
      • The identities role in the client's use case.
      • The authentication methods that can be used to authenticate as this identity:
        • One or more other Stellar addresses.
        • And/or, one or more phone numbers.
        • And/or, one or more email addresses.
        • And/or, one or more other external authentication methods.
  • The server verifies the JWT is valid according to SEP-10.
  • The server verifies that the account the JWT proves control of is the account being registered.
  • The server verifies that the account is not already registered.
  • The server stores the account address and alternative identities.
  • The server generates a unique random signing key for the account.
  • The server encrypts the signing secret key and stores it.
  • The server responds to the client with the signing public key.
  • The client adds the signing public key as a signer of the account with an appropriate weight.

A client can register with multiple servers and give each signing key a weight that is appropriate for the use case the client and servers are targeting. For example, if a client intends to use two servers that should individually have no control of the account but together are able to approve transactions, then the client could configure account thresholds to high 2, med 2, low 2, and assign weights 1 to both server signing keys.

A client can register with a single server and give the servers signing key a weight that is appropriate for the use case the client and server are targeting. For example, if a client intends to use a single server and give that server control of the account, then the client could configure account thresholds to high 1, med 1, low 1, and assign weight 1 to the server signing key.

The signing flow is as follows:

  • The client uses the servers authentication provider to get a JWT proving possession of the phone number, email address, or other identity.
  • Alternatively, the client uses SEP-10 to get a JWT proving high threshold control of another account that is listed as an alternative identity of the account to be accessed.
  • The client, authenticated as the external authentication method (e.g. phone, email, etc) or another account, requests the server to sign a transaction.
  • The server verifies that the JWT is valid according to the authentication provider's specification.
  • The server verifies that the external authentication method (e.g. phone, email, etc) or account in the JWT is an alternative identity of the account.
  • The server verifies that the source account of the transaction is one of:
    • The account the client has authenticated for.
    • In some unique cases an account the server knows definitively for the validity period of the transaction will not be authorized by the signing key.1
  • The server verifies that the source account of each operation in the transaction are one of:
    • Not set.
    • The account the client has authenticated for.
    • In some unique cases an account the server knows definitively for the validity period of the transaction will not be authorized by the signing key.1
  • The server signs the transaction with the signing secret key.
  • The server responds to the client with the signature.

The client repeats the signing flow with each server it needs to meet the accounts threshold to be able to successfully submit a transaction.

The client can use this process to sign a transaction with the Set Options operation to add a new signer to the account to regain control of an account of which they have lost the key, or to gain control of an account shared with them.

A client can also use the endpoints in the specification to:

  • Discover registered accounts that it has access to.
  • Update the identities associated with an account.
  • Find out if a new signing key is available due to signing key rotation.
  • Delete accounts.

Notes:

  1. See Endpoints POST /accounts/<address>/sign/<signing-address> for more details.

Use Cases

This protocol is intended to satisfy a wide range of use cases, but initially the two use cases mentioned under Motivation are apparent.

Use Case: Recover

An individual that expects to maybe lose access to their keys can use SEP-30 to recover access to their Stellar accounts.

A single identity is sufficient and specifying a role would be unnecessary. The individual registers the account with two or more servers and gives each server signer weights so that no individual server can control the account, but together they can approve transactions.

The individual can recover the account by authenticating with all servers and requesting all servers sign a transaction giving a new key signing weight sufficient to meet the high threshold of the account.

Use Case: Share

An individual that wishes to share an account with another user and allow that other user to gain access to the account by recovering it from two or more servers.

Multiple identities should be specified each with a unique role so that when each individual is authenticated using an identities authentication methods they can recognize their role in relation to the account. In this case using roles such as sender and receiver are appropriate.

Either individual can recover the account by authenticating with all servers and asking all servers to sign a transaction giving a new key signing weight sufficient to meet the high threshold of the account.

The receiver can accept the account and either take ownership of it or merge it into another account by authenticating with all servers and requesting all servers sign a transaction giving a new key signing weight sufficient to meet the high threshold of the account. The receiver can then merge the account into their primary account. If the receiver chooses to keep the account they can delete the account from the servers or replace the identities so that the sender is no longer an identity authorized to recover the account.

The sender may wish to recover the account if the receiver does not and can use the same process.

The sender and receiver can recognize their relationship to an account by inspecting the authenticated identities role.

Specification

Authentication

All endpoints require authentication in the form of a JWT token that is passed in the Authorization header. The JWT can be issued by two types of issuers. Some endpoints require a specific provider while others should function with either. The two issuers are:

  • SEP-10: A SEP-10 Web Auth server for proving high threshold control of an account. The SEP-10 server should be configured to only issue JWTs if signers prove they meet the high threshold on the account.
  • External: Defined by the implementer. Proves possession of an identity that is external to the Stellar network and can be any electronic or physical identity. Examples of authentication identities that could be used are authentication of a phone number, email addres, or with an OpenID Connect provider, or verifying a physical address, national identity document, passport. Any forms of identity may be supported including those not formally specified in this protocol.

Content Type

All endpoints accept in requests the following Content-Type:

  • application/json

All endpoints respond with content type:

  • application/json

Errors

If an error occurs when calling any endpoint, an appropriate HTTP status code will be returned along with an error response.

Status Code

Common HTTP status codes may be returned for a server. In particular the following are expected:

Status Code Name Reason
400 Bad Request The request is invalid in anyway.
401 Unauthorized No Authorization header has been provided or the contents of the header are not accepted as valid.
404 Not Found The path is not recognized by the server, or the address does not have an account, or the authenticated user does not have permission to access the account.
409 Conflict The account is already registered, when attempting to register an account that is already registered.

Response

Fields
Name Type Description
error string A description of the error.
Example
{
  "error": "..."
}

Common Fields

A set of common fields are used to describe an account in requests and responses on most endpoints.

Common Request Fields

Name Type Description
identities array A list of identities that if any one is authenticated will be able to gain control of this account.
identities[].role string The role of the identity. This value is not used by the server and is stored and echoed back in responses as a way for a client to know conceptually who each identity represents.
identities[].auth_methods array A list of authentication methods that can be used to authenticate as this identity.
identities[].auth_methods[].type string The type of identity. See Common Authentication Methods.
identities[].auth_methods[].value string The identifier or value that uniquely identifies the identity that if authenticated will be given full permissions of the account. For example if the type of authentication is an email address, the value is the email address.
Common Authentication Methods

Implementers define the external authentication methods supported by the implementation. If an implementation supports any of the following common authentication methods the type values below should be used along with the specifications for how to format the identifiers to improve interopability between clients and servers that may have multiple integraters.

Type Description
stellar_address A Stellar address in the strkey form G..., proven via SEP-10.
phone_number A phone number. When encoding a phone number the ITU-T recommendations E.123 and E.164 should be followed. The phone number should be formatted in international notation with a leading + as demonstrated in E.123 Section 2.5 to ensure phone numbers are consistently encoded and are globally unique. Spaces should be omitted.
email An email address.
Example (With One Identity)
{
  "identities": [
    {
      "role": "owner",
      "auth_methods": [
        { "type": "stellar_address", "value": "GDUA..." },
        { "type": "phone_number", "value": "+10000000001" },
        { "type": "email", "value": "[email protected]" }
      ]
    }
  ]
}
Example (With Multiple Roles)
{
  "identities": [
    {
      "role": "sender",
      "auth_methods": [
        { "type": "stellar_address", "value": "GDUA..." },
        { "type": "phone_number", "value": "+10000000001" },
        { "type": "email", "value": "[email protected]" }
      ]
    },
    {
      "role": "receiver",
      "auth_methods": [
        { "type": "stellar_address", "value": "GBEA..." },
        { "type": "phone_number", "value": "+10000000002" },
        { "type": "email", "value": "[email protected]" }
      ]
    }
  ]
}

Common Response Fields

Name Type Description
address string The Stellar account ID or address of the account.
identities array A list of identities that if any one is authenticated will be able to gain control of this account.
identities[].role string Same as request. See above.
identities[].authenticated boolean Optional. Present and true if the currently authenticated client is authenticated with the identity.
signers array The signers' public keys that the server can sign transactions with for this account when requested by an authenticated user, ordered from most recently added to least recently added.
signers[].key string The signer public key that the server can sign transactions with for this account when requested by an authenticated user.
Example (With One Role)
{
  "address": "GFDD...",
  "identities": [{ "role": "owner", "authenticated": true }],
  "signers": [{ "key": "GADF..." }]
}
Example (With Multiple Roles)
{
  "address": "GFDD...",
  "identities": [{ "role": "sender", "authenticated": true }, { "role": "receiver" }],
  "signers": [{ "key": "GADF..." }]
}

Endpoints

POST /accounts/<address>

This endpoint registers an account.

The owner identities are the alternative identities of the user who owns the account.

The other identities are the identities of any other person who the owner is declaring should be allowed to gain control of the account.

Authentication

SEP-10

Request
Fields

See Common Fields.

Example
{
  "identities": [
    {
      "role": "sender",
      "auth_methods": [
        { "type": "stellar_address", "value": "GDUA..." },
        { "type": "phone_number", "value": "+10000000001" },
        { "type": "email", "value": "[email protected]" }
      ]
    },
    {
      "role": "receiver",
      "auth_methods": [
        { "type": "stellar_address", "value": "GBEA..." },
        { "type": "phone_number", "value": "+10000000002" },
        { "type": "email", "value": "[email protected]" }
      ]
    }
  ]
}
Response
Fields

See Common Fields.

Example (With One Identity)
{
  "address": "GFDD...",
  "identities": [{ "role": "owner" }],
  "signers": [{ "key": "GADF..." }]
}
Example (With Multiple Identities)
{
  "address": "GFDD...",
  "identities": [{ "role": "sender" }, { "role": "receiver" }],
  "signers": [{ "key": "GADF..." }]
}

PUT /accounts/<address>

This endpoint updates the identities for the account. The identities should be entirely replaced with the identities provided in the request, and not merged. Either owner or other or both should be set. If one is currently set and the request does not include it, it is removed.

Authentication

SEP-10 or External.

Request
Fields

See Common Fields.

Example
{
  "identities": [
    {
      "role": "sender",
      "auth_methods": [
        { "type": "stellar_address", "value": "GDUA..." },
        { "type": "phone_number", "value": "+10000000001" },
        { "type": "email", "value": "[email protected]" }
      ]
    },
    {
      "role": "receiver",
      "auth_methods": [
        { "type": "stellar_address", "value": "GBEA..." },
        { "type": "phone_number", "value": "+10000000002" },
        { "type": "email", "value": "[email protected]" }
      ]
    }
  ]
}
Response
Fields

See Common Fields.

Example
{
  "address": "GFDD...",
  "identities": [{ "role": "sender" }, { "role": "receiver" }],
  "signers": [{ "key": "GADF..." }]
}

POST /accounts/<address>/sign/<signing-address>

This endpoint signs a transaction that has operations for the account using the signing key associated with the signing address specified in the path.

The signing address specified must be one of the signing keys that the server has provided as a signer. The client should use the signing address that has been added as a signer to the account. The server may generate new signing keys over time as a best practice in rotating keys. All keys generated will be available for signing. An account should check what signers are available periodically and update the signer on the account to be the most recently generated signer.

A server must only authorize operations in signed transactions that operate on the registered account that the client has authenticated for. This is to ensure that the server does not authorize operations for an account the client is not authorized. There are multiples ways to achieve this depending on the use cases of the server.

The simplest approach is to require the transaction to only contain operations for the authenticated account. The server can verify that the source account of the transaction and the source account of all operations in the transaction match the account in the request.

In some cases a server may need to sign transactions that contain other accounts. For example, a sponsoring account using operations defined in CAP-33. A server could be implemented to allow transactions to contain that specific sponsoring account as a source account. The server operator must ensure that the signing keys used by the server are never signers of the sponsoring account to ensure an authenticated client cannot sign for the sponsoring account.

The transaction can contain any operations, but it is anticipated for the use cases discussed earlier in this protocol that the transaction will contain an operation to add a new signer to the account and possibly to remove an old signer or to merge an account. The signature will be generated using the signing key that the server generated during registration for the account.

Authentication

SEP-10 or External.

Request
Fields
Name Type Description
transaction string A XDR base64 encoded Stellar transaction.
Example
{
  "transaction": "AAAAAHAHhQtYBh5F2zA6..."
}
Response
Fields
Name Type Description
signature string The base64 encoded signature that is the result of the server signing a transaction.
network_passphrase string The network passphrase used when generating a signature.
Example
{
  "signature": "YpVelqPAKsYTP...",
  "network_passphrase": "Test SDF Network ; September 2015"
}

GET /accounts/<address>

This endpoint returns the registered account’s details.

In this response and in other responses the identities are not included in the response to ensure that for shared accounts one person’s identities are not leaked to another.

Authentication

SEP-10 or External.

Response
Fields

See Common Fields.

Example
{
  "address": "GFDD...",
  "identities": [{ "role": "sender", "authenticated": true }, { "role": "receiver" }],
  "signers": [{ "key": "GADF..." }]
}

DELETE /accounts/<address>

This endpoint will delete the record for an account. This should be irrecoverable.

Authentication

SEP-10 or External.

Response
Fields

See Common Fields.

Example
{
  "address": "GFDD...",
  "identities": [{ "role": "sender", "authenticated": true }, { "role": "receiver" }],
  "signer": "GADF...",
  "signers": [{ "key": "GADF..." }]
}

GET /accounts

This endpoint will return a list of accounts that the JWT allows access to. This includes the account authenticated with a SEP-10 JWT, or any account that has the account authenticated as an alternative identity, or any account that has the phone number or email address or any other supported identity with a JWT from another authentication provider.

Authentication

SEP-10 or External.

Response
Query Parameters
Name Type Description
after string Used for cursor-based pagination to get results after the given cursor. Use the value of the address of the last account in the current page to get the next page.
Fields
Name Type Description
accounts array A list of accounts accessible by the authenticated client.
accounts[].* object See Common Fields.
Example
{
  "accounts": [
    {
      "address": "GEAC...",
      "identities": [{ "authenticated": true }],
      "signers": [{ "key": "GADF..." }]
    },
    {
      "address": "GFDD...",
      "identities": [{ "role": "sender", "authenticated": true }, { "role": "receiver" }],
      "signers": [{ "key": "GADF..." }]
    },
    {
      "address": "GACD...",
      "identities": [{ "role": "sender" }, { "role": "receiver", "authenticated": true }],
      "signers": [{ "key": "GADF..." }]
    }
  ]
}

Security Concerns

Building, hosting and using this system has numerous security concerns because a server is being delegated to be a signer of an account and will handle one or more signing keys for many accounts.

This list of concerns is not exhaustive.

JWT

Implementers should also consider JWT, encryption, secure coding, and general security best practices.

Verifying Identities

Implementers and users of the protocol must consider the risks of relying on alternative identities such as phone number or email to be definite proof of the identity of a client or user.

Signing Key Rotation

Implementers may choose to rotate the keys used as signers of the accounts for any reason, e.g. as a routine best practice, or in response to a compromised key. An implementor should maintain old signing keys so that accounts that have not added a new signing key are still able to use them.

A client can query the server for what signers the server has available for an account and should replace the signer on the account with the most recently generated signing key at its earliest convenience.

External Authentication

Implementers choose the external authentication methods supported by their implementation.

Implementers should consider the risks posed by the external authentication methods that are supported by their implementation. An implementer, and the client using the implementation, are responsible for evaluating whether the authentication method provides a level of security suitable for accounts that will be registered.

If an implementation supports a variety of external authentication methods the client must evaluate which are suitable for the account it is registering. For example, if a client considers one type of authentication to carry unacceptable risk for an account, it may choose to not use that form of authentication.

Clients can update an account registered, adding or removing external authentication methods. For example, if a client registered an account with a phone number and then later collects an email address from the account holder, the client could add email alongside the phone number, or it could add email and remove the phone number so that the account can only be recovered by email.

Limitations

This protocol discusses a phone and email authentication provider vaguely but does not provide any specifics to that specification. This is an area still under research and once a better definition for what the specification is it will either be added to this protocol, added as a separate protocol proposal, or referenced if it is already captured as a standard elsewhere.

Implementations

Go

Recoverysigner is implemented by the Stellar recoverysigner service, recoverysigner.