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

# Authentication

> Email/password login, 2FA, environment variables, and profile files.

<Warning>
  The first release of `stx-python` authenticates with **account email and password**, exchanging them for a short-lived JWT. API-key / signed-request auth is not yet supported — until it lands, use a dedicated account for production bots and don't share your personal credentials.
</Warning>

## How it works

1. The first authenticated call triggers a `login` mutation: email + password in, JWT out.
2. The JWT is cached on the `User` singleton — shared across `STX`, `AsyncSTX`, and `STXWebSocket` in the same process.
3. Every subsequent call attaches `Authorization: Bearer <jwt>`.
4. JWTs are valid for 60 minutes. The SDK preemptively refreshes at minute 59 via the `newToken` mutation. You do not have to handle expiry.

## Where credentials come from

The SDK resolves credentials with this precedence (highest wins):

<Steps>
  <Step title="Keyword arguments">
    ```python theme={null}
    STX(region="ontario", env="staging",
        email="you@example.com", password="...")
    ```

    Explicit, highest precedence. Useful in tests and scripts. **Don't hard-code passwords in production code.**
  </Step>

  <Step title="Environment variables">
    ```bash theme={null}
    export STX_EMAIL="you@example.com"
    export STX_PASSWORD="your-password"
    ```

    ```python theme={null}
    STX(region="ontario", env="staging")   # picks up env vars
    ```

    Recommended for CI and containers.
  </Step>

  <Step title="Profile file">
    `~/.stx/credentials` — AWS-CLI-style INI format:

    ```ini theme={null}
    [default]
    email = you@example.com
    password = your-password

    [prod-bot]
    email = bot@example.com
    password = bot-password
    ```

    ```python theme={null}
    STX(region="ontario", env="staging")                 # uses [default]
    STX(region="ontario", env="production", profile="prod-bot")
    ```

    Recommended for local development.
  </Step>

  <Step title="Defaults">
    No defaults — if none of the above provide credentials, the SDK raises `STXAuthenticationFailedException` on the first authenticated call.
  </Step>
</Steps>

## Two-factor authentication

If the account has 2FA enabled, the first call raises `STXTwoFactorRequiredException`. Catch it, collect the code that arrived via email, and call `confirm2Fa`:

```python theme={null}
from stx import STX
from stx.exceptions import STXTwoFactorRequiredException

client = STX(region="ontario", env="staging",
             email="you@example.com", password="...")

try:
    client.markets()
except STXTwoFactorRequiredException:
    code = input("2FA code from email: ")
    client.confirm2Fa(params={"code": code})
    client.markets()   # now works
```

The 2FA `session_id` is cached on the `User` singleton alongside the JWT, so subsequent calls in the same process don't re-prompt.

<Note>
  For headless bots, use a service account **without** 2FA enabled. The 2FA flow is interactive by design.
</Note>

## Token lifetime

|                              | Value                              |
| ---------------------------- | ---------------------------------- |
| Server-declared JWT lifetime | 60 minutes                         |
| SDK-side refresh trigger     | 59 minutes                         |
| Refresh mutation             | `newToken`                         |
| Shared across clients?       | Yes — same process, same singleton |

You can force a fresh token (for example, if the user's password was rotated externally):

```python theme={null}
from stx.user import User

User().clear()               # drops cached JWT + session
client.markets()         # next call re-authenticates
```

## Sharing auth across clients

The `User` singleton means one login covers all three clients:

```python theme={null}
from stx import STX, AsyncSTX, STXWebSocket

# Logs in once — JWT is cached on the singleton.
sync_client = STX(region="ontario", env="staging",
                  email="you@example.com", password="...")
sync_client.markets()

# These re-use the cached JWT — no second login.
async_client = AsyncSTX(region="ontario", env="staging")
ws_client    = STXWebSocket(region="ontario", env="staging")
```

## Troubleshooting

<AccordionGroup>
  <Accordion title="STXAuthenticationFailedException: 'Invalid email or password'">
    The server rejected your credentials. Check:

    * Is `STX_EMAIL` / `STX_PASSWORD` pointing at the right `env`? (staging vs production accounts are distinct.)
    * Did you recently rotate the password?
    * Try logging in through the web app with the same credentials.
  </Accordion>

  <Accordion title="STXTwoFactorRequiredException on every call">
    The 2FA `session_id` isn't being cached between script invocations. The singleton is process-scoped — if you're running a fresh Python process each time, 2FA will prompt every time. Use a service account without 2FA for CI/bots.
  </Accordion>

  <Accordion title="'missing credentials' but my env vars are set">
    Make sure the env vars are named exactly `STX_EMAIL` and `STX_PASSWORD` (not `STX_USERNAME` or similar). Check with `echo $STX_EMAIL` in the same shell you're running Python from.
  </Accordion>

  <Accordion title="STXTokenExpiredException in a long-running service">
    This should be rare — the SDK refreshes at 59 minutes automatically. If you see it, it usually means the `newToken` refresh itself failed (for example, the account was disabled, or the server was momentarily unreachable). The next call will attempt a fresh login.
  </Accordion>
</AccordionGroup>

## Security best practices

1. **Never commit credentials to git.** Use env vars or a profile file in `~/.stx/`, both `.gitignore`'d by convention.
2. **Rotate on compromise.** Log in to the web app and change the password — the SDK will re-authenticate on the next call.
3. **Use a dedicated account for bots.** Don't share your personal login with automation.
4. **Set file permissions on `~/.stx/credentials`.** Chmod to `600`:
   ```bash theme={null}
   chmod 600 ~/.stx/credentials
   ```
5. **Prefer staging during development.** `env="production"` touches real balances.

## Next

<CardGroup cols={2}>
  <Card title="Configuration" icon="sliders" href="/sdks/python/configuration">
    Regions, environments, and profile files in detail.
  </Card>

  <Card title="Errors & retries" icon="triangle-exclamation" href="/sdks/python/errors-and-retries">
    The full exception hierarchy and retry policy.
  </Card>
</CardGroup>
