Permalink
Switch branches/tags
Nothing to show
Find file Copy path
4e9aced Oct 10, 2018
2 contributors

Users who have contributed to this file

@tomquisel @nebolsin
170 lines (118 sloc) 10.6 KB

Preamble

SEP: 0010
Title: Stellar Web Authentication
Author: Sergey Nebolsin <sergey@mobius.network>, Tom Quisel <tom.quisel@gmail.com>
Status: Accepted
Created: 2018-07-31
Updated: 2018-08-14
Version 1.0.1

Simple Summary

This SEP defines the standard way for clients such as wallets or exchanges to create authenticated web sessions on behalf of a user who holds a Stellar account. A wallet may want to authenticate with any web service which requires a Stellar account ownership verification, for example, to upload KYC information to an anchor in an authenticated way as described in SEP-6.

Abstract

This protocol is a variation of mutual challenge-response, which uses Stellar transactions to encode challenges and responses.

The authentication flow is as follows:

  1. The client obtains a unique challenge, which is represented as specially formed Stellar transaction
  2. The client signs the transaction using the secret key for the user's Stellar account
  3. The client submits the signed challenge back to the server using token endpoint
  4. If the signature checks out, the server responds with a JWT that represents the user's session
  5. Any future calls to the server can be authenticated by including the JWT as a parameter

The flow achieves several things:

  • Both client and server part can be implemented using well-established Stellar libraries
  • The client can verify that the server holds the secret key to a particular account
  • The server can verify that the client holds the secret key to their account
  • The client is able to prove their identity using a Ledger or other hardware wallet as well as by having direct access to the secret key
  • The server can chose its own timeout for the user's session

Authentication Endpoint

A web service indicates that it supports user authentication via this protocol by specifying WEB_AUTH_ENDPOINT in their stellar.toml file. This is how a wallet knows where to find the authentication server. A web server is required to implement the following behavior for the web authentication endpoint:

Challenge

This endpoint must respond with a Stellar transaction signed by the server that has an invalid sequence number (0) and thus cannot be executed on the Stellar network. The client can then sign the transaction using standard Stellar libraries and submit it to token endpoint to prove that they control their account. This approach is compatible with hardware wallets such as Ledger. The client can also verify the server's signature to be sure the challenge is signed by the SIGNING_KEY from the server's stellar.toml.

Request

GET <WEB_AUTH_ENDPOINT>

Request Parameters:

Name Type Description
account G... string The stellar account that the wallet wishes to authenticate with the server

Example:

GET https://auth.example.com/?account=GCIBUCGPOHWMMMFPFTDWBSVHQRT4DIBJ7AD6BZJYDITBK2LCVBYW7HUQ

Response

On success the endpoint should return 200 OK HTTP status code and a JSON object with a transaction field containing an XDR-encoded Stellar transaction with the following:

  • source account set to server's signing account
  • invalid sequence number (set to 0) so the transaction cannot be run on the Stellar network
  • time bounds: {min: now(), max: now() + 300 } (we recommend expiration of 5 minutes to give user time to sign transaction)
  • operations: manage_data(source: client_account, key: '<anchor name> auth', value: random_nonce())
    • The value of key is not important, but can be the name of the anchor followed by auth. It can be at most 64 bytes.
    • The value must be a 64 byte long base64 encoded cryptographic-quality random string
  • signature by the web service signing account

Example:

{
  "transaction": "AAAAAGjeCRajN67nRkVtYO+lpxax9gvitX9FxhZYGXQvs16hAAAAZAAAAAAAAAAAAAAAAQAAAABbcutKAAAAAFty7HYAAAAAAAAAAQAAAAEAAAAAVIx5odtAgqQ+dp4m4QfWntHbOq0hxRCLGI+2Sm0P6EMAAAAKAAAAC01vYml1cyBhdXRoAAAAAAEAAABAG01TL/Ha0YGVrAF6t0UEKP/0Q/NDUymciQBA/CXzYMVlEx2KcHrq3MkpQ9+9sCbCiOYa7wCtusa1tHKygvZRSwAAAAAAAAABL7NeoQAAAEC9v5jdxReIxoCcCXw90dVsIpXwHXkSHUUthCs98D/zpd6TNPvcMgUsQd6cDHzjNk+/00P8M5bHP4rIpFTm7MwN"
}

You can examine the example challenge transaction in the XDR Viewer.

Every other HTTP status code will be considered an error. For example:

{
   "error": "The provided account has requested too many challenges recently. Try again later."
}

Token

This endpoint accepts a signed challenge transaction, validates it and responds with a session JSON Web Token authenticating the user.

Client submits a challenge transaction (that was previously returned by the challenge endpoint) as a HTTP POST request to WEB_AUTH_ENDPOINT using one of the following formats (both should be equally supported by the server):

  • Content-Type: application/x-www-form-urlencoded, body: transaction=<signed XDR (URL-encoded)>)
  • Content-Type: application/json, body: {"transaction": "<signed XDR>"}

To validate the challenge transaction the following steps are performed by the server. If any of the listed steps fail, then the authentication request must be rejected — that is, treated by the application as an invalid input.

  • decode the received input as a base64-urlencoded XDR representation of Stellar transaction envelope;
  • verify that transaction source account is equal to the server's signing key;
  • verify that transaction has time bounds set, and that current time is between the minimum and maximum bounds;
  • verify that transaction contains a single Manage Data operation and it's source account is not null;
  • verify that transaction envelope has a correct signature by server's signing key;
  • verify that transaction envelope has a correct signature by the operation's source account;
  • use operations's source account to determine the authenticating client and perform any additional service-specific validations.

Upon successful validation service responds with a session JWT, containing the following claims:

  • iss (the principal that issued a token, RFC7519, Section 4.1.1) — the URI of the web service (https://example.com)
  • sub (the principal that is the subject of the JWT, RFC7519, Section 4.1.2) — the public key of the authenticating Stellar account (G...)
  • iat (the time at which the JWT was issued RFC7519, Section 4.1.6) — current timestamp (1530644093)
  • exp (the expiration time on or after which the JWT must not be accepted for processing, RFC7519, Section 4.1.4) — a server can pick its own expiration period for the token, however 24 hours is recommended (1530730493)
  • jti (the unique identifier for the JWT, RFC7519, Section 4.1.7) — hex-encoded hash of the challenge transaction (f0e754c6ab988eb5fb2811c2cacc4d3d2aa4334763b8df7285ef341921e2530a)

Request

POST <WEB_AUTH_ENDPOINT>

Request Parameters:

Name Type Description
transaction string base64 encoded signed challenge transaction XDR

Example:

POST https://auth.example.com/
Content-Type: application/json

{"transaction": "AAAAAGjeCRajN67nRkVtYO+lpxax9gvitX9FxhZYGXQvs16hAAAAZAAAAAAAAAAAAAAAAQAAAABbcutKAAAAAFty7HYAAAAAAAAAAQAAAAEAAAAAVIx5odtAgqQ+dp4m4QfWntHbOq0hxRCLGI+2Sm0P6EMAAAAKAAAAC01vYml1cyBhdXRoAAAAAAEAAABAG01TL/Ha0YGVrAF6t0UEKP/0Q/NDUymciQBA/CXzYMVlEx2KcHrq3MkpQ9+9sCbCiOYa7wCtusa1tHKygvZRSwAAAAAAAAACL7NeoQAAAEC9v5jdxReIxoCcCXw90dVsIpXwHXkSHUUthCs98D/zpd6TNPvcMgUsQd6cDHzjNk+/00P8M5bHP4rIpFTm7MwNbQ/oQwAAAEAz+6EANIKAAR8G62OkGzbnkxgyYuFwbbCwvbDbkk8db31I/EyR0gRpcxv7zzBAkn8g48N6x1huJhTUO0CPl28M"}

You can examine the example signed challenge transaction in the XDR Viewer.

Response

If the web service successfully validates the submitted challenge transaction, the endpoint should return 200 OK HTTP status code and a JSON object with the following fields:

Name Type Description
token string The JWT that a user can use to authenticate future endpoint calls with the anchor

Example:

{
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJHQTZVSVhYUEVXWUZJTE5VSVdBQzM3WTRRUEVaTVFWREpIREtWV0ZaSjJLQ1dVQklVNUlYWk5EQSIsImp0aSI6IjE0NGQzNjdiY2IwZTcyY2FiZmRiZGU2MGVhZTBhZDczM2NjNjVkMmE2NTg3MDgzZGFiM2Q2MTZmODg1MTkwMjQiLCJpc3MiOiJodHRwczovL2ZsYXBweS1iaXJkLWRhcHAuZmlyZWJhc2VhcHAuY29tLyIsImlhdCI6MTUzNDI1Nzk5NCwiZXhwIjoxNTM0MzQ0Mzk0fQ.8nbB83Z6vGBgC1X9r3N6oQCFTBzDiITAfCJasRft0z0"
}

Check the example session token on JWT.IO.

Every other HTTP status code will be considered an error. For example:

{
   "error": "The provided transaction is not valid"
}