# 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


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.yield.fi/earn-with-yieldfi/integration-sdk/authentication/token-management.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
