Stellar Authentication (SEP-10)
Overview
SEP-10 (Stellar Web Authentication) enables wallet applications to create authenticated sessions with Stellar anchors by proving control over a Stellar account. Once authenticated, wallets receive a JSON Web Token (JWT) that they use in subsequent requests to the anchor's standardized services.
For the complete specification, see SEP-0010: Stellar Web Authentication.
The Anchor Platform implements SEP-10 with support for:
- Challenge/Response Flow: GET
/authto request a challenge, POST/authto validate and receive a JWT - Client Attribution: Optional verification of client application identity for noncustodial wallets
- Custodial Wallet Support: Support for custodial wallets that manage user accounts
- Multiple Home Domains: Support for multiple domains and wildcard patterns
Typical Authentication Flow
- The Client requests a unique challenge from the Server
- The Client verifies and signs the challenge
- The Client submits the signed challenge to the Server
- The Server verifies the challenge and responds with a JWT session token
Enable SEP-10
To enable SEP-10, set the following environment variables in your dev.env file.
- bash
# dev.env
SEP10_ENABLED=true
SEP10_HOME_DOMAINS=localhost:8080
SECRET_SEP10_SIGNING_SEED="a Stellar private key"
SECRET_SEP10_JWT_SECRET="a secret encryption key"
Required Configuration (If Enabled)
| Variable | Default | Description |
|---|---|---|
SEP10_ENABLED | false | Set to true to enable SEP-10 authentication |
SEP10_HOME_DOMAINS | localhost:8080 | List of home domains (comma-separated). Supports wildcard patterns like *.stellar.org. The home_domain must match the host where your stellar.toml file is served. |
SECRET_SEP10_SIGNING_SEED | Required | The private key corresponding to the SIGNING_KEY in your stellar.toml file. Used to sign authentication challenges. Wallets verify this signature before signing and returning the challenge. |
SECRET_SEP10_JWT_SECRET | Required | The encryption key used to sign and verify JWT tokens issued to authenticated wallets. |
The SIGNING_KEY in your stellar.toml file must be the public key derived from SECRET_SEP10_SIGNING_SEED. Wallets will verify that challenge transactions are signed by this key.
Optional Configuration
- bash
# dev.env
# Optional: Specify web_auth_domain (default: first home_domain if only one is specified)
SEP10_WEB_AUTH_DOMAIN=localhost:8080
# Optional: Challenge transaction timeout in seconds (default: 900)
SEP10_AUTH_TIMEOUT=900
# Optional: JWT token timeout in seconds (default: 86400 = 24 hours)
SEP10_JWT_TIMEOUT=86400
# Optional: Require Authorization header in GET /auth requests (default: false)
SEP10_REQUIRE_AUTH_HEADER=false
# Optional: Client attribution requirement (default: false)
SEP10_CLIENT_ATTRIBUTION_REQUIRED=false
# Optional: Client allow list (default: empty, all configured clients allowed)
# Comma-separated list of client names that are allowed to authenticate
SEP10_CLIENT_ALLOW_LIST=client1,client2
| Variable | Default | Description |
|---|---|---|
SEP10_WEB_AUTH_DOMAIN | First home_domain if only one is specified, otherwise empty | The web_auth_domain property used in SEP-10 responses. Required if you have multiple home_domains or use wildcard patterns. Must match the host of the SEP server. |
SEP10_AUTH_TIMEOUT | 900 | Time in seconds that a challenge transaction remains valid. Clients must sign and submit the challenge within this window. |
SEP10_JWT_TIMEOUT | 86400 | Time in seconds that an issued JWT token remains valid. After expiration, clients must re-authenticate. |
SEP10_REQUIRE_AUTH_HEADER | false | If true, requires a valid Authorization header (Bearer JWT) in GET /auth challenge requests. This prevents unauthorized access to the endpoint and is useful for re-authentication flows where clients need to refresh their JWT tokens. |
SEP10_CLIENT_ATTRIBUTION_REQUIRED | false | If true, noncustodial wallets must provide a client_domain in challenge requests. Requires client configuration (see below). |
SEP10_CLIENT_ALLOW_LIST | Empty (all configured clients allowed) | Comma-separated list of client names that are allowed to authenticate. Only relevant when SEP10_CLIENT_ATTRIBUTION_REQUIRED=true. If empty, all configured clients are allowed. |
Multiple Home Domains: If you specify multiple home_domains (e.g., ap.stellar.org,*.sdp.stellar.org), you must also set SEP10_WEB_AUTH_DOMAIN to specify which domain hosts the authentication endpoint.
Client Attribution
Client attribution allows you to restrict authentication to specific wallet applications and verify their identity. This is an optional feature that should only be enabled if it's a business requirement.
By default, the Anchor Platform allows anyone with a Stellar account to authenticate. Client attribution is only needed if you want to:
- Restrict authentication to specific wallet applications
- Verify the identity of noncustodial wallet applications
- Track which wallet applications your users are using
Enabling Client Attribution
- bash
# dev.env
SEP10_CLIENT_ATTRIBUTION_REQUIRED=true
When SEP10_CLIENT_ATTRIBUTION_REQUIRED=true, noncustodial wallets must:
- Provide a
client_domainparameter in the challenge request - Sign the challenge transaction with the
SIGNING_KEYfrom that domain'sstellar.tomlfile - Have their domain listed in your client configuration
Client Configuration
Configure allowed clients in your YAML configuration file:
- YAML
clients:
# Each item in the list may contain the following fields:
# - name: (required) the name of the client
# - type: (required) `custodial` or `noncustodial`
#
# If the type is `custodial`,
# - signing_keys: (required) the custodial SEP-10 signing key(s) of the client.
# - callback_urls.sep6: (optional) the URL of the client's SEP-6 callback API endpoint.
# - callback_urls.sep24: (optional) the URL of the client's SEP-24 callback API endpoint.
# - callback_urls.sep31: (optional) the URL of the client's SEP-31 callback API endpoint.
# - callback_urls.sep12: (optional) the URL of the client's SEP-12 callback API endpoint.
# - allow_any_destination: (optional) default to false. If set to true, allows any destination for deposits.
# - destination_accounts: (optional) list of accounts allowed to be used for the deposit.
# If allow_any_destination is set to true, this configuration option is ignored.
#
# If the type is `noncustodial`,
# - domains: (required) the domains of the client.
# - callback_urls.sep6: (optional) the URL of the client's SEP-6 callback API endpoint.
# - callback_urls.sep24: (optional) the URL of the client's SEP-24 callback API endpoint.
# - callback_urls.sep31: (optional) the URL of the client's SEP-31 callback API endpoint.
# - callback_urls.sep12: (optional) the URL of the client's SEP-12 callback API endpoint.
# custodial client
- name: bluecorp
type: custodial
signing_keys: "the signing key 1 of bluecorp","the signing key 2 of bluecorp"
callback_urls:
sep6: https://callback.bluecorp.com/api/v1/anchor/callback/sep6
sep12: https://callback.bluecorp.com/api/v1/anchor/callback/sep12
allow_any_destination: false
destination_accounts: GA...
# noncustodial client
- name: pinkcorp
type: noncustodial
domains: pinkcorp.com
callback_urls:
sep6: https://callback.pinkcorp.com/api/v2/anchor/callback/sep6
sep12: https://callback.pinkcorp.com/api/v2/anchor/callback/sep12
- name: redcorp
type: custodial
signing_keys: "the signing key of redcorp",
Or configure via environment variables:
- bash
# dev.env
# custodial client
CLIENTS[0]_NAME=bluecorp
CLIENTS[0]_TYPE=custodial
CLIENTS[0]_SIGNING_KEYS="the signing key 1 of bluecorp","the signing key 2 of bluecorp"
CLIENTS[0]_ALLOW_ANY_DESTINATION=false
CLIENTS[0]_DESTINATION_ACCOUNTS=GA...
# noncustodial client
CLIENTS[1]_NAME=pinkcorp
CLIENTS[1]_TYPE=noncustodial
CLIENTS[1]_DOMAINS=pinkcorp.com
# custodial client
CLIENTS[2]_NAME=redcorp
CLIENTS[2]_TYPE=custodial
CLIENTS[2]_SIGNING_KEYS="the signing key of redcorp"
Configure stellar.toml
Update your stellar.toml file to advertise SEP-10 support. Wallets discover your authentication endpoint through this file.
- TOML
# dev.stellar.toml
SIGNING_KEY = "add your signing key here (public key from SECRET_SEP10_SIGNING_SEED)"
WEB_AUTH_ENDPOINT = "http://localhost:8080/auth"
These fields should match the configuration options set in the Enable SEP-10 section above.
WEB_AUTH_ENDPOINT - The URL where the authentication service is running. This is the URL that clients will use to authenticate with the anchor. The endpoint must support:
GET <WEB_AUTH_ENDPOINT>- Request a challengePOST <WEB_AUTH_ENDPOINT>- Exchange signed challenge for session JWT
SIGNING_KEY - The public key corresponding to the private key specified in SECRET_SEP10_SIGNING_SEED. This key is used to sign authentication challenges presented to wallet applications.
SIGNING_KEY: Must be the public key derived fromSECRET_SEP10_SIGNING_SEEDWEB_AUTH_ENDPOINT: Usehttps://in production. The path/authis the standard SEP-10 endpoint.- Host Matching: The host in
WEB_AUTH_ENDPOINTshould match one of yourSEP10_HOME_DOMAINS(or theSEP10_WEB_AUTH_DOMAINif specified).
How to Test the Authentication Flow
The SEP-10 authentication flow consists of two steps:
-
GET
/auth- Request a challenge transaction- Parameters:
account(required),memo(optional),home_domain(optional),client_domain(optional) - Returns: A challenge transaction in XDR format
- Parameters:
-
POST
/auth- Validate the signed challenge and receive a JWT- Body:
{ "transaction": "<signed_challenge_xdr>" } - Returns:
{ "token": "<jwt_token>" }
- Body:
The JWT token should be included in subsequent API requests as a Bearer token in the Authorization header.
Testing Your Configuration: You can test SEP-10 authentication using curl and Stellar CLI. For more information about Stellar CLI, see the Stellar CLI documentation.
# Verify if `stellar` command line is installed
stellar --version
# List your Stellar keys/identities
stellar keys ls
# Get your account ID (public key) and secret seed
# Replace 'alice' with your identity name from `stellar keys ls`
IDENTITY_NAME="alice"
ACCOUNT_ID=$(stellar keys public-key "$IDENTITY_NAME")
SECRET_SEED=$(stellar keys secret "$IDENTITY_NAME")
# Step 1: Request challenge and save the transaction XDR
CHALLENGE_RESPONSE=$(curl -s "http://localhost:8080/auth?account=$ACCOUNT_ID")
CHALLENGE_XDR=$(echo "$CHALLENGE_RESPONSE" | jq -r '.transaction')
# Step 2: Sign the challenge transaction using Stellar CLI
# Note: The output includes info messages; the signed XDR is on the last line
SIGNED_CHALLENGE_XDR=$(echo "$CHALLENGE_XDR" | stellar tx sign --sign-with-key "$SECRET_SEED" 2>&1 | tail -1)
# Step 3: Submit the signed challenge and receive JWT token
curl -X POST "http://localhost:8080/auth" \
-H "Content-Type: application/json" \
-d "{\"transaction\": \"$SIGNED_CHALLENGE_XDR\"}"