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

# Authentication

> Connect your C# automation to Speckle Server — personal access tokens, environment variables, and desktop login

Connect your automation to Speckle Server. Before your code can load model data or publish results, SpeckleSharp needs an **Account** (a token plus server and user metadata) and an **IClient** built from it.

**What this page covers:** the three .NET ways to obtain an Account — personal access token, interactive browser login, and locally stored accounts. **When to read it:** before any server call in a new app. **Read next:** [Build your first model analysis tool](/developers/sdks/dotnet/guides/build-your-first-model-analysis-tool) or [Automate with scripts](/developers/sdks/dotnet/getting-started/scripts-and-notebooks).

<Info>
  For how to create a personal access token or register an OAuth application, see [Building with PATs](/developers/authentication/pats) and [OAuth 2.0](/developers/authentication/oauth2). This page covers the .NET-specific code that consumes them.
</Info>

Speckle.Sdk exposes three ways to get an `Account`:

* **Personal access token** — scripts, services, and CI (recommended default)
* **Interactive browser login** — desktop and connector apps that should integrate with Speckle's existing account store
* **Locally stored accounts** — reuse a login from Speckle desktop connectors

<Warning>
  **Prefer a personal access token or your own OAuth flow over `Accounts.db`.** `IAccountManager.AuthenticateAccount` (below) always writes the resulting account to a local SQLite database (`Accounts.db`) — there's no way to opt out. That's the right behavior for a desktop connector that should share login state with Rhino, Revit, Grasshopper, and other Speckle apps on the same machine. It's very rarely what you want in a script, a server-side service, a CI pipeline, or a multi-user web backend, where a token you manage yourself (env var, secret manager, or your own OAuth exchange) is simpler and doesn't leave credentials on disk outside your control.
</Warning>

## Choosing an Authentication Method

* **A script, service, automation, or CI/CD pipeline** — use a [personal access token](#token-based-authentication-recommended-for-aec-scripts) via `IAccountFactory.CreateAccount`. Doesn't touch `Accounts.db` — in-memory only.
* **A multi-user server or web backend that already manages its own user tokens** — perform your own OAuth exchange (see [OAuth 2.0](/developers/authentication/oauth2)), then pass the resulting token to `IAccountFactory.CreateAccount`. Doesn't touch `Accounts.db` — in-memory only.
* **A desktop connector or CLI tool meant to share login state with Speckle's desktop ecosystem** — use [interactive login](#interactive-login-connectors-and-desktop-apps) via `IAccountManager.AuthenticateAccount`. Always writes to `Accounts.db`, by design.
* **Any app reusing a login a user already created via a Speckle desktop connector or `AuthenticateAccount`** — use [locally stored accounts](#reusing-locally-stored-accounts) via `GetAccounts`/`GetDefaultAccount`. Read-only access to `Accounts.db`.

## Token-based authentication (recommended for AEC scripts)

The recommended approach for most AEC automation scripts: build an `Account` from a personal access token using `IAccountFactory`.

```csharp Example lines icon="https://mintcdn.com/speckle/VtRPWzmN-ULoLfIv/images/developers/sdks/csharp.svg?fit=max&auto=format&n=VtRPWzmN-ULoLfIv&q=85&s=f2970e3b8bd4a2c7899b46211a42f251" theme={null}
using Microsoft.Extensions.DependencyInjection;
using Speckle.Sdk.Api;
using Speckle.Sdk.Credentials;

var accountFactory = provider.GetRequiredService<IAccountFactory>();
var account = await accountFactory.CreateAccount(
    new Uri("https://app.speckle.systems"),
    speckleToken: "your_token_here" // In production, use environment variables!
);

using var client = provider.GetRequiredService<IClientFactory>().Create(account);
Console.WriteLine($"Authenticated as: {account.userInfo.name}");
```

<Note>
  `IAccountFactory.CreateAccount` fetches user and server info from the token and returns an `Account` object. It does not write to the local account store — it's a lightweight factory for in-memory use, ideal for scripts, services, and CI.
</Note>

## Use Environment Variables (Recommended)

```csharp Example lines icon="https://mintcdn.com/speckle/VtRPWzmN-ULoLfIv/images/developers/sdks/csharp.svg?fit=max&auto=format&n=VtRPWzmN-ULoLfIv&q=85&s=f2970e3b8bd4a2c7899b46211a42f251" theme={null}
var token = Environment.GetEnvironmentVariable("SPECKLE_TOKEN")
    ?? throw new InvalidOperationException("SPECKLE_TOKEN environment variable not set");
var serverUrl = Environment.GetEnvironmentVariable("SPECKLE_SERVER") ?? "https://app.speckle.systems";

var account = await accountFactory.CreateAccount(new Uri(serverUrl), token);
```

<Tabs>
  <Tab title="Linux/macOS">
    ```bash theme={null}
    export SPECKLE_TOKEN="your_token_here"
    export SPECKLE_SERVER="https://app.speckle.systems"
    ```
  </Tab>

  <Tab title="Windows (PowerShell)">
    ```powershell theme={null}
    $env:SPECKLE_TOKEN="your_token_here"
    $env:SPECKLE_SERVER="https://app.speckle.systems"
    ```
  </Tab>

  <Tab title="CI/CD">
    ```yaml theme={null}
    # .github/workflows/example.yml
    env:
      SPECKLE_TOKEN: ${{ secrets.SPECKLE_TOKEN }}
    ```
  </Tab>
</Tabs>

## Interactive login (connectors and desktop apps)

Avoid this section unless you are building a connector or desktop tool. For scripts, QA automations, and Grasshopper send/receive, use a PAT from the section above.

For desktop or connector-style applications where a user should sign in through the browser **and** you want that login to be reusable across Speckle's desktop ecosystem, use `IAccountManager.AuthenticateAccount`. This opens a browser window and completes an OAuth PKCE flow.

```csharp Example lines icon="https://mintcdn.com/speckle/VtRPWzmN-ULoLfIv/images/developers/sdks/csharp.svg?fit=max&auto=format&n=VtRPWzmN-ULoLfIv&q=85&s=f2970e3b8bd4a2c7899b46211a42f251" theme={null}
using Speckle.Sdk.Credentials;

var accountManager = provider.GetRequiredService<IAccountManager>();
var account = await accountManager.AuthenticateAccount(
    new Uri("https://app.speckle.systems"),
    TimeSpan.FromMinutes(1),
    CancellationToken.None
);
```

<Warning>
  `AuthenticateAccount` **unconditionally** persists the resulting account to a local SQLite database file at the current user's application data folder (`.../Speckle/Accounts.db`) — the same store used by Speckle's desktop connectors. There is no in-memory-only mode for this method. If you need interactive OAuth login **without** writing to that shared store — for example, a web backend performing OAuth on behalf of many users — implement your own PKCE/authorization-code exchange (see [OAuth 2.0](/developers/authentication/oauth2)) and build the `Account` from the resulting token with `IAccountFactory.CreateAccount` instead, which never touches disk.
</Warning>

## Reusing Locally Stored Accounts

If a user has already signed in via a Speckle desktop connector, or via `AuthenticateAccount` above, retrieve their stored accounts instead of prompting again:

```csharp Example lines icon="https://mintcdn.com/speckle/VtRPWzmN-ULoLfIv/images/developers/sdks/csharp.svg?fit=max&auto=format&n=VtRPWzmN-ULoLfIv&q=85&s=f2970e3b8bd4a2c7899b46211a42f251" theme={null}
var accountManager = provider.GetRequiredService<IAccountManager>();

// All accounts for a specific server
var accounts = accountManager.GetAccounts(new Uri("https://app.speckle.systems"));

// Or the user's default account across all servers
var defaultAccount = accountManager.GetDefaultAccount();

if (defaultAccount is not null)
{
    using var client = provider.GetRequiredService<IClientFactory>().Create(defaultAccount);
}
```

<Warning>
  Older `AccountManager` methods such as `AddAccount` and `GetLocalAccounts` are obsolete and throw at runtime. Use `AuthenticateAccount`, `GetAccounts`, and `GetDefaultAccount` instead.
</Warning>

## Different Speckle Servers

```csharp Example lines icon="https://mintcdn.com/speckle/VtRPWzmN-ULoLfIv/images/developers/sdks/csharp.svg?fit=max&auto=format&n=VtRPWzmN-ULoLfIv&q=85&s=f2970e3b8bd4a2c7899b46211a42f251" theme={null}
// Public Speckle server
var account = await accountFactory.CreateAccount(new Uri("https://app.speckle.systems"), token);

// Self-hosted server
var account = await accountFactory.CreateAccount(new Uri("https://speckle.mycompany.com"), token);
```

## Checking Authentication Status

```csharp Example lines icon="https://mintcdn.com/speckle/VtRPWzmN-ULoLfIv/images/developers/sdks/csharp.svg?fit=max&auto=format&n=VtRPWzmN-ULoLfIv&q=85&s=f2970e3b8bd4a2c7899b46211a42f251" theme={null}
if (!string.IsNullOrEmpty(account.token))
{
    Console.WriteLine("✓ Authenticated");
    Console.WriteLine($"Logged in as: {account.userInfo.name} ({account.userInfo.email})");
}
```

## Common Authentication Errors

<AccordionGroup>
  <Accordion title="SpeckleException: GraphQL response indicated that the ActiveUser could not be found">
    **Cause:** The token is invalid, expired, or has been revoked.

    **Solution:** Generate a new personal access token and verify there are no extra spaces when copying it.
  </Accordion>

  <Accordion title="No accounts returned by GetAccounts / GetDefaultAccount">
    **Cause:** No account has been authenticated on this machine yet.

    **Solution:** Use token-based authentication via `IAccountFactory.CreateAccount`, or call `AuthenticateAccount` to sign in interactively first.
  </Accordion>

  <Accordion title="HTTP connection errors to a self-hosted server">
    **Cause:** The server URL is incorrect, or the server uses a self-signed certificate.

    **Solution:** Verify the server URL, check network/firewall settings, and ensure the certificate is trusted by the host machine — Speckle.Sdk does not expose a certificate-bypass option.
  </Accordion>
</AccordionGroup>

## Security Best Practices

<Check>
  **Do:**

  * Store tokens in environment variables or a secret manager
  * Use scoped tokens with the minimum permissions your application needs
  * Revoke tokens when they're no longer needed
</Check>

<Warning>
  **Don't:**

  * Commit tokens to version control
  * Share tokens between team members or applications
  * Use personal access tokens in client-side or distributed desktop code — prefer OAuth for multi-user applications
</Warning>

## Next Steps

<CardGroup cols={3}>
  <Card title="Build your first model analysis tool" icon="chart-bar" href="/developers/sdks/dotnet/guides/build-your-first-model-analysis-tool">
    Load model data after authenticating
  </Card>

  <Card title="Automate with scripts" icon="terminal" href="/developers/sdks/dotnet/getting-started/scripts-and-notebooks">
    Bootstrap and Receive2
  </Card>

  <Card title="Core concepts" icon="book" href="/developers/sdks/dotnet/concepts/overview">
    Platform map and mental model
  </Card>
</CardGroup>
