> ## 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.

# Authenticate with the SportsX C# SDK

> Log in with email and password, handle two-factor authentication, keep JWTs refreshed automatically, and manage terms-and-conditions acceptance.

All authenticated endpoints require a JWT. `STX.Sdk` acquires, caches, and refreshes the token for you — in most apps you call `LoginAsync` once at startup and never touch the token directly. The sections below cover the cases where you need more control.

## Simple login

```csharp theme={null}
using STX.Sdk.Services;

var login = serviceProvider.GetRequiredService<STXLoginService>();

var user = await login.LoginAsync(
    email:    "you@example.com",
    password: "your-password");

Console.WriteLine($"Logged in as {user.UserId}");
```

`LoginAsync` returns an `STXUserDataCollection` with the following fields:

| Field                            | Description                                              |
| -------------------------------- | -------------------------------------------------------- |
| `Token`                          | Bearer token attached to every subsequent GraphQL call   |
| `RefreshToken`                   | Used by `STXTokenService.RefreshTokenAsync`              |
| `UserId`, `UserUid`, `SessionId` | Identifiers used by WebSocket channel subscriptions      |
| `CurrentLoginAt`                 | Timestamp of the login event                             |
| `PromptTncAcceptance`            | `true` when the user still needs to accept updated T\&Cs |

The token is automatically cached in `STXUserStorage` and attached to every subsequent GraphQL call. You never need to pass it manually.

## Two-factor authentication

If the account has 2FA enabled, the initial `LoginAsync` call returns partial user data. Authentication is not complete until you confirm the one-time code:

```csharp theme={null}
var partial = await login.LoginAsync(email, password);

if (partial.PromptTwoFactor)
{
    Console.Write("2FA code: ");
    var code = Console.ReadLine();

    var tokenService = serviceProvider.GetRequiredService<STXTokenService>();
    var confirmed = await tokenService.Confirm2FAAsync(
        code:      code!,
        sessionId: partial.SessionId,
        email:     email);

    Console.WriteLine($"Authenticated: {confirmed.UserId}");
}
```

<Note>
  The 2FA flow calls the same `confirm2Fa` GraphQL mutation used by other SportsX SDK clients.
</Note>

## Keep the session alive

Long-running bots should refresh the JWT before it expires. Pass `keepSessionAlive: true` and the SDK's `STXSessionBackgroundService` handles refresh in the background:

```csharp theme={null}
await login.LoginAsync(
    email,
    password,
    keepSessionAlive: true);
```

Two requirements apply:

* The service provider must be hosted under `Host.CreateDefaultBuilder` so background services actually run.
* Credentials stay in memory in `STXUserStorage` so the background service can re-login if the refresh token itself expires.

### Manual token refresh

If you prefer explicit control over refresh timing — for example in a minimal script that doesn't run under a full host — wrap your trading calls like this:

```csharp theme={null}
async Task<T> WithSession<T>(Func<Task<T>> call)
{
    try { return await call(); }
    catch (STXTokenExpiredException)
    {
        await _tokens.RefreshTokenAsync();
        return await call();
    }
    catch (STXSessionExpiredException)
    {
        await _login.LoginAsync(_email, _password);
        return await call();
    }
}
```

## Accept terms and conditions

If `PromptTncAcceptance` is `true` after login, subsequent authenticated calls will fail until the user accepts the latest terms. Pass `checkTermsAndConditions: true` to surface the T\&Cs text for display:

```csharp theme={null}
await login.LoginAsync(
    email,
    password,
    checkTermsAndConditions: true);
```

Once the user has explicitly agreed in your UI, record their acceptance:

```csharp theme={null}
var tnc = serviceProvider.GetRequiredService<STXTermsAndConditionsService>();
var latest = await tnc.GetTermsAndConditionsAsync();
await tnc.AcceptTermsAndConditionsAsync(latest.Version);
```

<Warning>
  Only call `AcceptTermsAndConditionsAsync` after the user has read and agreed to the terms in your UI. Accepting on their behalf without consent may violate applicable regulations.
</Warning>

## Logout

There is no server-side logout call. To end the session, clear the stored token:

```csharp theme={null}
var storage = serviceProvider.GetRequiredService<STXUserStorage>();
storage.Clear();
```

This also stops any active background services and closes WebSocket channels on their next tick.

## Authentication errors

| Exception                      | Cause                                  | Recovery                                                      |
| ------------------------------ | -------------------------------------- | ------------------------------------------------------------- |
| `STXWrongCredentialsException` | Email or password rejected             | Prompt the user for fresh credentials                         |
| `STXTokenExpiredException`     | JWT expired; refresh token still valid | Call `STXTokenService.RefreshTokenAsync`                      |
| `STXSessionExpiredException`   | Both token and refresh token expired   | Call `STXLoginService.LoginAsync` again                       |
| `STXGeoComplyException`        | Geo-compliance check failed            | User is outside a permitted jurisdiction — surface to your UI |

See [Errors & retries](/sdks/csharp/errors-and-retries) for the full exception list and recovery patterns.
