> For the complete documentation index, see [llms.txt](https://docs.yield.fi/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.yield.fi/earn-with-yieldfi/integration-sdk/authentication/token-management.md).

# Token Management

This guide covers how to manage authentication tokens, including storage, refresh, and expiration handling.

### Token Types

#### Access Token

* **Purpose**: Authenticate API requests
* **Lifetime**: Typically 15 minutes
* **Format**: JWT (JSON Web Token)
* **Usage**: Include in `Authorization` header for authenticated requests

#### Refresh Token

* **Purpose**: Obtain new access tokens without re-authentication
* **Lifetime**: Typically 7 days
* **Format**: Opaque token string
* **Usage**: Exchange for new access token when current one expires

### Storing Tokens

The SDK does **not** store tokens internally. You must manage token storage in your application.

#### Browser Storage Options

**localStorage (Persistent)**

```typescript
// Store tokens
localStorage.setItem("accessToken", authResponse.accessToken);
localStorage.setItem("refreshToken", authResponse.refreshToken);

// Retrieve tokens
const accessToken = localStorage.getItem("accessToken");
const refreshToken = localStorage.getItem("refreshToken");

// Clear tokens
localStorage.removeItem("accessToken");
localStorage.removeItem("refreshToken");
```

**Pros**: Persists across browser sessions\
**Cons**: Accessible to JavaScript (XSS risk)

**sessionStorage (Session-only)**

```typescript
// Store tokens
sessionStorage.setItem("accessToken", authResponse.accessToken);

// Retrieve tokens
const accessToken = sessionStorage.getItem("accessToken");
```

**Pros**: Cleared when tab closes\
**Cons**: Still accessible to JavaScript

**HTTP-Only Cookies (Recommended for Server-Side)**

For server-side applications, use HTTP-only cookies set by your backend:

```typescript
// Backend sets cookies after login
// Frontend automatically includes cookies in requests
// Cookies are not accessible to JavaScript (XSS protection)
```

### Checking Token Expiration

Use JWT utilities to check token expiration:

```typescript
import { isTokenExpired, getTimeUntilExpiration } from "yieldfi-sdk";

const accessToken = localStorage.getItem("accessToken");

// Check if token is expired
if (isTokenExpired(accessToken)) {
  console.log("Token is expired, need to refresh");
}

// Check with buffer (refresh if expiring in 5 minutes)
if (isTokenExpired(accessToken, 300)) {
  console.log("Token expiring soon, refreshing proactively");
}

// Get time until expiration
const secondsLeft = getTimeUntilExpiration(accessToken);
console.log(`Token expires in ${secondsLeft} seconds`);
```

### Refreshing Tokens

When an access token expires, use the refresh token to get a new one:

```typescript
import { YieldFiSDK } from "yieldfi-sdk";

const sdk = await YieldFiSDK.create({
  gatewayUrl: "https://gw.yield.fi",
});

const refreshToken = localStorage.getItem("refreshToken");

try {
  // Refresh access token
  const newTokens = await sdk.auth.refresh({
    refreshToken: refreshToken,
  });

  // Update stored tokens
  localStorage.setItem("accessToken", newTokens.accessToken);
  localStorage.setItem("refreshToken", newTokens.refreshToken);
} catch (error) {
  // Refresh token expired or invalid
  // Redirect to login
  localStorage.removeItem("accessToken");
  localStorage.removeItem("refreshToken");
  // Redirect to login page
}
```

#### Alternative: Refresh with API Key

You can also refresh using an API key:

```typescript
const newTokens = await sdk.auth.refresh({
  apiKey: "yfi_...",
});
```

### Automatic Token Refresh

Implement automatic token refresh to improve user experience:

```typescript
import { isTokenExpired } from "yieldfi-sdk";

async function getValidAccessToken(): Promise<string | null> {
  let accessToken = localStorage.getItem("accessToken");
  const refreshToken = localStorage.getItem("refreshToken");

  // Check if token is expired or expiring soon (5 minute buffer)
  if (!accessToken || isTokenExpired(accessToken, 300)) {
    if (!refreshToken) {
      // No refresh token, user needs to login again
      return null;
    }

    try {
      // Refresh the token
      const sdk = await YieldFiSDK.create({
        gatewayUrl: "https://gw.yield.fi",
      });

      const newTokens = await sdk.auth.refresh({ refreshToken });
      accessToken = newTokens.accessToken;

      // Update stored tokens
      localStorage.setItem("accessToken", newTokens.accessToken);
      localStorage.setItem("refreshToken", newTokens.refreshToken);
    } catch (error) {
      // Refresh failed, clear tokens
      localStorage.removeItem("accessToken");
      localStorage.removeItem("refreshToken");
      return null;
    }
  }

  return accessToken;
}

// Use in API calls
async function makeAuthenticatedRequest() {
  const accessToken = await getValidAccessToken();
  if (!accessToken) {
    // Redirect to login
    return;
  }

  // Make API call with valid token
  const transactions = await sdk.vault.getTransactions(
    { chainId: 1, page: 1, pageSize: 20 },
    accessToken
  );
}
```

### Token Refresh Interceptor

For applications using HTTP clients, implement a token refresh interceptor:

```typescript
import axios from "axios";
import { YieldFiSDK } from "yieldfi-sdk";

const sdk = await YieldFiSDK.create({
  gatewayUrl: "https://gw.yield.fi",
});

// Create axios instance
const apiClient = axios.create({
  baseURL: "https://gw.yield.fi",
});

// Request interceptor: Add access token
apiClient.interceptors.request.use(async (config) => {
  const accessToken = await getValidAccessToken();
  if (accessToken) {
    config.headers.Authorization = `Bearer ${accessToken}`;
  }
  return config;
});

// Response interceptor: Handle 401 and refresh token
apiClient.interceptors.response.use(
  (response) => response,
  async (error) => {
    const originalRequest = error.config;

    // If 401 and haven't retried yet
    if (error.response?.status === 401 && !originalRequest._retry) {
      originalRequest._retry = true;

      const refreshToken = localStorage.getItem("refreshToken");
      if (refreshToken) {
        try {
          const newTokens = await sdk.auth.refresh({ refreshToken });
          localStorage.setItem("accessToken", newTokens.accessToken);
          localStorage.setItem("refreshToken", newTokens.refreshToken);

          // Retry original request with new token
          originalRequest.headers.Authorization = `Bearer ${newTokens.accessToken}`;
          return apiClient(originalRequest);
        } catch (refreshError) {
          // Refresh failed, redirect to login
          localStorage.removeItem("accessToken");
          localStorage.removeItem("refreshToken");
          window.location.href = "/login";
          return Promise.reject(refreshError);
        }
      }
    }

    return Promise.reject(error);
  }
);
```

### Logout

To logout, revoke tokens on the server and clear local storage:

```typescript
import { YieldFiSDK } from "yieldfi-sdk";

const sdk = await YieldFiSDK.create({
  gatewayUrl: "https://gw.yield.fi",
});

const accessToken = localStorage.getItem("accessToken");

try {
  // Revoke tokens on server
  await sdk.auth.logout(accessToken);
} catch (error) {
  // Even if logout fails, clear local tokens
  console.error("Logout error:", error);
} finally {
  // Always clear local storage
  localStorage.removeItem("accessToken");
  localStorage.removeItem("refreshToken");
  localStorage.removeItem("user");
}
```

### Security Considerations

1. **Never expose refresh tokens** - Keep them server-side if possible
2. **Use HTTPS** - Always use HTTPS to protect tokens in transit
3. **Implement CSRF protection** - Use CSRF tokens for state-changing operations
4. **Token rotation** - Consider rotating refresh tokens on each refresh
5. **Monitor token usage** - Log and monitor token refresh patterns for anomalies

### Next Steps

* User Consent - Manage user consent records
* API Reference - Learn about authenticated APIs
