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

# Authentication

> Choose and implement the right auth pattern

Authentication determines how your MCP server gets credentials to access external services. Choose the right pattern based on who provides the credentials and how they should be managed.

| Type            | Who provides credentials       | Example                       |
| --------------- | ------------------------------ | ----------------------------- |
| **OAuth**       | User authorizes via OAuth flow | Linear, GitHub, Slack         |
| **Credentials** | User enters in Gumstack UI     | OpenAI API key, custom tokens |
| **None**        | Developer sets via env vars    | Shared API keys, public APIs  |

<Warning>
  Auth type cannot be changed after server creation. Choose carefully!
</Warning>

## OAuth

Best for services where users need to connect their own accounts. Gumstack handles the OAuth flow, token storage, and automatic refresh—you just implement the provider.

### Configure your OAuth app

When registering an OAuth application with the third-party service (e.g., Linear, GitHub, Slack), set the **redirect / callback URL** to:

```
https://api.gumstack.com/auth/callback
```

This is the URL Gumstack uses to receive the authorization code after a user approves access.

### Implement AuthProvider

Create a class that defines how to authenticate with your service:

```python theme={"dark"}
import os
from mcp.gumstack import AuthProvider, TokenResponse

class LinearAuthProvider(AuthProvider):
    name = "linear"

    def get_url(self, redirect_uri: str, state: str) -> str:
        client_id = os.environ["LINEAR_CLIENT_ID"]
        return f"https://linear.app/oauth/authorize?client_id={client_id}&redirect_uri={redirect_uri}&state={state}&response_type=code&scope=read,write"

    async def exchange(self, code: str, redirect_uri: str) -> TokenResponse:
        # Exchange code for tokens with Linear API
        return TokenResponse(
            access_token=response["access_token"],
            refresh_token=response.get("refresh_token"),
            expires_in=response.get("expires_in")
        )

    async def refresh(self, refresh_token: str) -> TokenResponse:
        # Refresh expired token
        return TokenResponse(access_token=new_token)

    async def get_nickname(self, access_token: str) -> str:
        # Display name for connected account
        return "user@company.com"
```

### Register with GumstackHost

Register your auth provider so Gumstack can use it:

```python theme={"dark"}
from mcp.gumstack import GumstackHost

host = GumstackHost(mcp)
host.register_auth(LinearAuthProvider())
host.run()
```

### Use in tools

Access the user's credentials in your tools:

```python theme={"dark"}
@mcp.tool()
async def list_issues() -> list[Issue]:
    creds = await get_credentials()
    token = creds["access_token"]
    # Call Linear API with token
```

## Credentials

Best for services that use API keys or tokens that users provide themselves. Users enter their credentials in the Gumstack UI, and Gumstack securely stores and provides them to your server.

Define the fields you need in `config.yaml`:

```yaml theme={"dark"}
auth:
  type: cred
  credentials:
    - name: "api_key"
      label: "API Key"
      description: "Your OpenAI API key"
      placeholder: "sk-..."
      secret: true
```

Then access them in your tools:

```python theme={"dark"}
@mcp.tool()
async def generate(prompt: str) -> str:
    creds = await get_credentials()
    api_key = creds["api_key"]
    # Call OpenAI API
```

## None (Environment Variables)

Best for shared API keys that you (the developer) provide, or for public APIs that don't require user-specific credentials. You set the credentials once in the Gumstack dashboard, and they're available to all users.

```yaml theme={"dark"}
auth:
  type: none
```

Set your credentials in the Gumstack dashboard under **Environment Variables**, then access them in your tools:

```python theme={"dark"}
@mcp.tool()
def get_weather(city: str) -> Weather:
    creds = get_credentials()  # Note: sync, not async
    api_key = creds["api_key"]
    # Call weather API
```

<Note>
  With `auth.type: none`, `get_credentials()` is synchronous and reads directly
  from environment variables.
</Note>

## Reserved Environment Variables

Gumstack reserves certain environment variable prefixes for internal use. These will be rejected if you try to use them:

* `GUMLOOP_*`
* `GUMSTACK_*`
