# User Session Management

Manage user sessions, access tokens, and authentication state in your Unity game.

## Session behavior

Sessions in Openfort use a **sliding session** model:

* Sessions last **30 days** by default
* Sessions automatically refresh when the user is active
* No manual refresh token exchange is required
* If a session hasn't been accessed for 30 days, it expires

Session tokens are securely signed using HMAC-SHA-256 and verified against Openfort's servers on each request.

## Methods

### GetAccessToken

Retrieve the current access token for authenticated API requests.

**Method Signature:**

```csharp
public UniTask<string> GetAccessToken()
```

**Parameters:**

* None

**Returns:**

* `UniTask<string>` - The current access token

**Example:**

```csharp
using System;
using UnityEngine;
using UnityEngine.Networking;
using Cysharp.Threading.Tasks;
using Openfort.OpenfortSDK;

public class TokenManager : MonoBehaviour
{
    private OpenfortSDK openfort;

    private async void Start()
    {
        openfort = await OpenfortSDK.Init("YOUR_OPENFORT_PUBLISHABLE_KEY");
    }

    public async UniTask<string> GetCurrentToken()
    {
        try
        {
            string accessToken = await openfort.GetAccessToken();
            Debug.Log($"Access token retrieved: {accessToken.Substring(0, 20)}...");
            return accessToken;
        }
        catch (Exception e)
        {
            Debug.LogError($"Failed to get access token: {e.Message}");
            throw;
        }
    }
}
```

### GetUser

Get the currently authenticated user's information.

**Method Signature:**

```csharp
public async UniTask<User> GetUser()
```

**Parameters:**

* None

**Returns:**

* `UniTask<User>` - Current user information

**User Structure:**

```csharp
public class User
{
    public string Id { get; set; }                    // Unique user identifier
    public string Email { get; set; }                 // User's email address
    public string Name { get; set; }                  // User's display name
    public string Image { get; set; }                 // URL to profile image
    public bool? EmailVerified { get; set; }          // Whether email is verified
    public string CreatedAt { get; set; }             // ISO timestamp when created
    public string UpdatedAt { get; set; }             // ISO timestamp when updated
    public bool? IsAnonymous { get; set; }            // Whether user is anonymous
    public string PhoneNumber { get; set; }           // User's phone number
    public bool? PhoneNumberVerified { get; set; }    // Whether phone is verified
    public List<UserAccount> LinkedAccounts { get; set; } // Linked OAuth/wallet accounts
}

public class UserAccount
{
    public string Provider { get; set; }        // OAuth provider or "wallet"
    public string AccountId { get; set; }       // Provider-specific account ID
    public string ChainType { get; set; }       // EVM or SVM (for wallets)
    public string ChainId { get; set; }         // Chain ID (for wallets)
    public string ConnectorType { get; set; }   // Wallet connector type
    public string WalletClientType { get; set; } // Wallet client type
    public long? CreatedAt { get; set; }        // Timestamp when linked
    public long? UpdatedAt { get; set; }        // Timestamp when updated
}
```

**Example:**

```csharp
public async UniTask<User> GetCurrentUser()
{
    try
    {
        var user = await openfort.GetUser();

        Debug.Log($"User ID: {user.Id}");
        Debug.Log($"Email: {user.Email}");
        Debug.Log($"Email Verified: {user.EmailVerified}");
        Debug.Log($"Is Anonymous: {user.IsAnonymous}");

        return user;
    }
    catch (Exception e)
    {
        Debug.LogError($"Failed to get user: {e.Message}");
        throw;
    }
}
```

### ValidateAndRefreshToken

Validate the current session and extend its expiration if needed. This method checks if the stored session is still valid and automatically extends the session duration when the user is active (sliding session model).

**Method Signature:**

```csharp
public async UniTask ValidateAndRefreshToken(bool forceRefresh = false)
```

**Parameters:**

* `bool forceRefresh` - Force refresh the token even if not expired (optional, default: false)

**Returns:**

* `UniTask` - Completes when validation/refresh is done

**Example:**

```csharp
public async UniTask RefreshSession()
{
    try
    {
        await openfort.ValidateAndRefreshToken(false);

        Debug.Log("Session validated/refreshed successfully");
    }
    catch (Exception e)
    {
        Debug.LogError($"Failed to refresh session: {e.Message}");
        throw;
    }
}
```

### StoreCredentials

Store authentication credentials for session persistence.

**Method Signature:**

```csharp
public async UniTask StoreCredentials(AuthCredentialsRequest request)
```

**Parameters:**

* `AuthCredentialsRequest request` - Credentials to store

**Returns:**

* `UniTask` - Completes when credentials are stored

**AuthCredentialsRequest Structure:**

```csharp
public class AuthCredentialsRequest
{
    public string player;       // Player identifier
    public string accessToken;  // Access token for authentication
    public string refreshToken; // Refresh token for authentication

    public AuthCredentialsRequest(string player, string accessToken, string refreshToken)
    {
        this.player = player;
        this.accessToken = accessToken;
        this.refreshToken = refreshToken;
    }
}
```

**Example:**

```csharp
public async UniTask SaveCredentials(string playerId, string accessToken, string refreshToken)
{
    try
    {
        var request = new AuthCredentialsRequest(playerId, accessToken, refreshToken);
        await openfort.StoreCredentials(request);

        Debug.Log("Credentials stored successfully");
    }
    catch (Exception e)
    {
        Debug.LogError($"Failed to store credentials: {e.Message}");
        throw;
    }
}
```

### Logout

Log out the current user and clear stored session data.

**Method Signature:**

```csharp
public async UniTask Logout()
```

**Parameters:**

* None

**Returns:**

* `UniTask` - Completes when logout is finished

**Example:**

```csharp
public async UniTask LogoutUser()
{
    try
    {
        await openfort.Logout();
        Debug.Log("User logged out successfully");
    }
    catch (Exception e)
    {
        Debug.LogError($"Logout failed: {e.Message}");
        throw;
    }
}
```

### SetCallTimeout

Set the timeout duration for SDK API calls.

**Method Signature:**

```csharp
public void SetCallTimeout(int ms)
```

**Parameters:**

* `int ms` - Timeout in milliseconds

**Example:**

```csharp
// Set timeout to 30 seconds
openfort.SetCallTimeout(30000);
```

### ClearCache

Clear cached data from the SDK.

**Method Signature:**

```csharp
public void ClearCache(bool includeDiskFiles)
```

**Parameters:**

* `bool includeDiskFiles` - Whether to also clear disk-stored cache files

**Example:**

```csharp
// Clear memory cache only
openfort.ClearCache(false);

// Clear both memory and disk cache
openfort.ClearCache(true);
```

### ClearStorage

Clear all stored SDK data including credentials.

**Method Signature:**

```csharp
public void ClearStorage()
```

**Parameters:**

* None

**Example:**

```csharp
// Clear all stored data
openfort.ClearStorage();
```

## Complete session management example

Here's a complete example of managing sessions in Unity:

```csharp
using System;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.SceneManagement;
using Cysharp.Threading.Tasks;
using Openfort.OpenfortSDK;
using Openfort.OpenfortSDK.Model;

public class SessionManager : MonoBehaviour
{
    private OpenfortSDK openfort;
    private User currentUser;

    public event Action<User> OnUserChanged;
    public event Action OnLogout;

    private async void Start()
    {
        openfort = await OpenfortSDK.Init(
            "YOUR_OPENFORT_PUBLISHABLE_KEY",
            "YOUR_SHIELD_PUBLISHABLE_KEY"
        );

        // Set timeout for API calls
        openfort.SetCallTimeout(30000); // 30 seconds

        // Try to restore previous session
        await TryRestoreSession();
    }

    private async UniTask TryRestoreSession()
    {
        try
        {
            await openfort.ValidateAndRefreshToken(false);
            currentUser = await openfort.GetUser();
            OnUserChanged?.Invoke(currentUser);
            Debug.Log($"Session restored for user: {currentUser.Id}");
        }
        catch (Exception e)
        {
            Debug.Log($"No valid session found: {e.Message}");
            // User needs to log in
        }
    }

    public UniTask<string> GetAccessToken()
    {
        try
        {
            return openfort.GetAccessToken();
        }
        catch (Exception e)
        {
            Debug.LogError($"Error getting access token: {e.Message}");
            throw;
        }
    }

    public async UniTask<User> GetCurrentUser()
    {
        if (currentUser != null)
            return currentUser;

        try
        {
            currentUser = await openfort.GetUser();
            return currentUser;
        }
        catch (Exception e)
        {
            Debug.LogError($"Error getting user: {e.Message}");
            throw;
        }
    }

    public async UniTask MakeAuthenticatedRequest(string endpoint)
    {
        try
        {
            string accessToken = await GetAccessToken();

            using (UnityWebRequest request = UnityWebRequest.Get(endpoint))
            {
                request.SetRequestHeader("Authorization", $"Bearer {accessToken}");
                await request.SendWebRequest();

                if (request.result == UnityWebRequest.Result.Success)
                {
                    string response = request.downloadHandler.text;
                    Debug.Log($"API response: {response}");
                }
                else
                {
                    Debug.LogError($"API request failed: {request.error}");
                }
            }
        }
        catch (Exception e)
        {
            Debug.LogError($"API request failed: {e.Message}");
            throw;
        }
    }

    public async UniTask LogoutUser()
    {
        try
        {
            await openfort.Logout();
            currentUser = null;

            // Clear any cached data
            openfort.ClearCache(true);

            Debug.Log("User logged out successfully");
            OnLogout?.Invoke();

            // Return to login screen
            SceneManager.LoadScene("LoginScene");
        }
        catch (Exception e)
        {
            Debug.LogError($"Logout error: {e.Message}");
            throw;
        }
    }

    public bool IsLoggedIn()
    {
        return currentUser != null;
    }

    public bool IsGuestUser()
    {
        return currentUser?.IsAnonymous ?? false;
    }
}
```

## Auth events

The SDK provides auth events to monitor authentication state changes:

```csharp
using Openfort.OpenfortSDK;
using Openfort.OpenfortSDK.Model;
using Openfort.OpenfortSDK.Event;

public class AuthEventHandler : MonoBehaviour
{
    private OpenfortSDK openfort;

    private async void Start()
    {
        openfort = await OpenfortSDK.Init("YOUR_OPENFORT_PUBLISHABLE_KEY");

        // Subscribe to auth events
        openfort.OnAuthEvent += HandleAuthEvent;
    }

    private void HandleAuthEvent(OpenfortAuthEvent authEvent)
    {
        switch (authEvent)
        {
            case OpenfortAuthEvent.LoggingIn:
                Debug.Log("Login in progress...");
                break;
            case OpenfortAuthEvent.LoginSuccess:
                Debug.Log("Login successful!");
                break;
            case OpenfortAuthEvent.LoginFailed:
                Debug.Log("Login failed");
                break;
            case OpenfortAuthEvent.LoggingOut:
                Debug.Log("Logout in progress...");
                break;
            case OpenfortAuthEvent.LogoutSuccess:
                Debug.Log("Logout successful!");
                break;
            case OpenfortAuthEvent.LogoutFailed:
                Debug.Log("Logout failed");
                break;
            case OpenfortAuthEvent.ReloggingIn:
                Debug.Log("Re-logging in with saved credentials...");
                break;
            case OpenfortAuthEvent.ReloginSuccess:
                Debug.Log("Re-login successful!");
                break;
            case OpenfortAuthEvent.ReloginFailed:
                Debug.Log("Re-login failed");
                break;
        }
    }

    private void OnDestroy()
    {
        if (openfort != null)
        {
            openfort.OnAuthEvent -= HandleAuthEvent;
        }
    }
}
```

## Auth event types

```csharp
public enum OpenfortAuthEvent
{
    // Login events
    LoggingIn,           // Started login process
    LoginFailed,         // Login failed
    LoginSuccess,        // Successfully logged in

    // Logout events
    LoggingOut,          // Started logout process
    LogoutFailed,        // Logout failed
    LogoutSuccess,       // Successfully logged out

    // Re-login events (using saved credentials)
    ReloggingIn,         // Started re-login with saved credentials
    ReloginFailed,       // Re-login failed
    ReloginSuccess,      // Successfully re-logged in

    // Reconnection events
    Reconnecting,        // Started reconnect process
    ReconnectFailed,     // Reconnect failed
    ReconnectSuccess,    // Successfully reconnected

    // Credential check events
    CheckingForSavedCredentials,      // Checking for saved credentials
    CheckForSavedCredentialsFailed,   // Failed to check
    CheckForSavedCredentialsSuccess   // Successfully checked
}
```
