> ## Documentation Index
> Fetch the complete documentation index at: https://developers.stellar.org/llms.txt
> Use this file to discover all available pages before exploring further.

# Stellar Authentication (SEP-10)

> SEP-10 (Stellar Web Authentication) enables wallet applications to create authenticated sessions with Stellar anchors by proving control over a Stellar account.

## 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-10: Stellar Web Authentication](https://github.com/stellar/stellar-protocol/blob/master/ecosystem/sep-0010.md).

The Anchor Platform implements SEP-10 with support for:

* **Challenge/Response Flow**: GET `/auth` to request a challenge, POST `/auth` to 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

1. The **Client** requests a unique challenge from the **Server**
2. The **Client** verifies and signs the challenge
3. The **Client** submits the signed challenge to the **Server**
4. 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 bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
# 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. |

> [!WARNING]
>
> 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 bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
# 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. |

> [!TIP]
>
> **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.

> [!NOTE]
>
> 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 bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
# dev.env
SEP10_CLIENT_ATTRIBUTION_REQUIRED=true
```

When `SEP10_CLIENT_ATTRIBUTION_REQUIRED=true`, noncustodial wallets must:

1. Provide a `client_domain` parameter in the challenge request
2. Sign the challenge transaction with the `SIGNING_KEY` from that domain's `stellar.toml` file
3. Have their domain listed in your client configuration

### Client Configuration

Configure allowed clients in your YAML configuration file:

```yaml YAML theme={"theme":{"light":"github-light","dark":"github-dark"}}
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 bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
# 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 TOML theme={"theme":{"light":"github-light","dark":"github-dark"}}
# 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](#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 challenge
* `POST <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.

> [!WARNING]
>
> * **`SIGNING_KEY`**: Must be the public key derived from `SECRET_SEP10_SIGNING_SEED`
> * **`WEB_AUTH_ENDPOINT`**: Use `https://` in production. The path `/auth` is the standard SEP-10 endpoint.
> * **Host Matching**: The host in `WEB_AUTH_ENDPOINT` should match one of your `SEP10_HOME_DOMAINS` (or the `SEP10_WEB_AUTH_DOMAIN` if specified).

## How to Test the Authentication Flow

The SEP-10 authentication flow consists of two steps:

1. **GET `/auth`** - Request a challenge transaction
   * Parameters: `account` (required), `memo` (optional), `home_domain` (optional), `client_domain` (optional)
   * Returns: A challenge transaction in XDR format

2. **POST `/auth`** - Validate the signed challenge and receive a JWT
   * Body: `{ "transaction": "<signed_challenge_xdr>" }`
   * Returns: `{ "token": "<jwt_token>" }`

The JWT token should be included in subsequent API requests as a Bearer token in the `Authorization` header.

> [!TIP]
>
> **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](https://developers.stellar.org/docs/tools/cli).
>
> ```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
> # 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\"}"
> ```

[sep1-ap]: https://developers.stellar.org/docs/platforms/anchor-platform/sep-guide/sep1.md

[sep-10]: https://github.com/stellar/stellar-protocol/blob/master/ecosystem/sep-0010.md
