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

# Session Authentication

> Browser-based authentication for web applications

# Session Authentication

Session authentication is designed for browser-based applications where users log in through the FLTR web interface. It uses HTTP-only cookies for secure, stateless authentication.

## Overview

Session authentication provides:

* **15,000 requests/hour** rate limit
* **HTTP-only cookies** to prevent XSS attacks
* **CSRF protection** built-in
* **Automatic session management** by the browser
* **Same security** as OAuth without the complexity

## When to Use Sessions

**Best for:**

* Single-page applications (SPAs)
* Server-rendered web apps
* Admin dashboards
* Internal tools

**Not recommended for:**

* Mobile apps (use OAuth)
* Server-to-server integrations (use API keys)
* Third-party integrations (use OAuth)

## Quick Start

<Steps>
  <Step title="Enable Session Auth">
    Configure your application to use credentials:

    ```javascript theme={null}
    fetch('https://api.fltr.com/v1/datasets', {
      credentials: 'include'  // Send cookies with request
    })
    ```
  </Step>

  <Step title="Redirect to Login">
    Send users to the FLTR login page:

    ```javascript theme={null}
    window.location.href = 'https://www.tryfltr.com/login?redirect_uri=' +
      encodeURIComponent(window.location.href);
    ```
  </Step>

  <Step title="Make API Calls">
    After login, session cookies are automatically included:

    ```javascript theme={null}
    const response = await fetch('https://api.fltr.com/v1/datasets', {
      credentials: 'include'
    });
    ```
  </Step>
</Steps>

## Implementation

### Frontend (React Example)

```javascript theme={null}
import { useEffect, useState } from 'react';

function App() {
  const [datasets, setDatasets] = useState([]);
  const [isAuthenticated, setIsAuthenticated] = useState(false);

  useEffect(() => {
    checkAuth();
  }, []);

  // Check if user is authenticated
  async function checkAuth() {
    try {
      const response = await fetch('https://api.fltr.com/v1/auth/session', {
        credentials: 'include'
      });

      if (response.ok) {
        setIsAuthenticated(true);
        loadDatasets();
      }
    } catch (error) {
      console.error('Not authenticated');
    }
  }

  // Load datasets
  async function loadDatasets() {
    const response = await fetch('https://api.fltr.com/v1/datasets', {
      credentials: 'include'
    });

    const data = await response.json();
    setDatasets(data.datasets);
  }

  // Login redirect
  function login() {
    const redirectUri = encodeURIComponent(window.location.href);
    window.location.href = `https://www.tryfltr.com/login?redirect_uri=${redirectUri}`;
  }

  // Logout
  async function logout() {
    await fetch('https://api.fltr.com/v1/auth/logout', {
      method: 'POST',
      credentials: 'include'
    });

    setIsAuthenticated(false);
    setDatasets([]);
  }

  if (!isAuthenticated) {
    return (
      <div>
        <h1>Welcome to FLTR</h1>
        <button onClick={login}>Login</button>
      </div>
    );
  }

  return (
    <div>
      <h1>My Datasets</h1>
      <button onClick={logout}>Logout</button>
      <ul>
        {datasets.map(dataset => (
          <li key={dataset.id}>{dataset.name}</li>
        ))}
      </ul>
    </div>
  );
}

export default App;
```

### Backend (Express.js Example)

If you need server-side session management:

```javascript theme={null}
import express from 'express';
import session from 'express-session';
import RedisStore from 'connect-redis';
import { createClient } from 'redis';

const app = express();

// Redis client for session storage
const redisClient = createClient();
await redisClient.connect();

// Session middleware
app.use(session({
  store: new RedisStore({ client: redisClient }),
  secret: 'your-secret-key',
  resave: false,
  saveUninitialized: false,
  cookie: {
    secure: true,      // HTTPS only
    httpOnly: true,    // Prevent JS access
    sameSite: 'lax',   // CSRF protection
    maxAge: 24 * 60 * 60 * 1000  // 24 hours
  }
}));

// Proxy requests to FLTR API
app.get('/api/datasets', async (req, res) => {
  if (!req.session.fltrAccessToken) {
    return res.status(401).json({ error: 'Not authenticated' });
  }

  const response = await fetch('https://api.fltr.com/v1/datasets', {
    headers: {
      'Authorization': `Bearer ${req.session.fltrAccessToken}`
    }
  });

  const data = await response.json();
  res.json(data);
});

// Login callback
app.get('/auth/callback', async (req, res) => {
  const { code } = req.query;

  // Exchange code for access token (OAuth flow)
  const tokenResponse = await fetch('https://www.tryfltr.com/oauth/token', {
    method: 'POST',
    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
    body: new URLSearchParams({
      grant_type: 'authorization_code',
      code,
      client_id: process.env.FLTR_CLIENT_ID,
      client_secret: process.env.FLTR_CLIENT_SECRET,
      redirect_uri: 'http://localhost:3000/auth/callback'
    })
  });

  const tokens = await tokenResponse.json();

  // Store in session
  req.session.fltrAccessToken = tokens.access_token;
  req.session.fltrRefreshToken = tokens.refresh_token;

  res.redirect('/');
});

// Logout
app.post('/auth/logout', (req, res) => {
  req.session.destroy();
  res.json({ success: true });
});

app.listen(3000);
```

## CORS Configuration

For browser-based requests, configure CORS properly:

### Development

```javascript theme={null}
// Allow credentials in development
fetch('https://api.fltr.com/v1/datasets', {
  credentials: 'include',  // Important!
  headers: {
    'Content-Type': 'application/json'
  }
})
```

### Production

Add your domain to FLTR's allowed origins:

1. Go to **Settings** → **CORS**
2. Add your production domain: `https://yourdomain.com`
3. Save changes

FLTR will send these CORS headers:

```
Access-Control-Allow-Origin: https://yourdomain.com
Access-Control-Allow-Credentials: true
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Headers: Content-Type, Authorization
```

## CSRF Protection

Session authentication includes built-in CSRF protection using the double-submit cookie pattern.

### How It Works

1. FLTR sets a CSRF token in a cookie
2. Your app reads the cookie and sends it in a header
3. FLTR validates the header matches the cookie

### Implementation

```javascript theme={null}
// Get CSRF token from cookie
function getCsrfToken() {
  const cookies = document.cookie.split(';');
  for (let cookie of cookies) {
    const [name, value] = cookie.trim().split('=');
    if (name === 'XSRF-TOKEN') {
      return decodeURIComponent(value);
    }
  }
  return null;
}

// Include CSRF token in requests
async function makeRequest(url, options = {}) {
  const csrfToken = getCsrfToken();

  const response = await fetch(url, {
    ...options,
    credentials: 'include',
    headers: {
      ...options.headers,
      'X-XSRF-TOKEN': csrfToken,
      'Content-Type': 'application/json'
    }
  });

  return response;
}

// Usage
await makeRequest('https://api.fltr.com/v1/datasets', {
  method: 'POST',
  body: JSON.stringify({ name: 'New Dataset' })
});
```

### Axios Configuration

Axios automatically handles CSRF tokens:

```javascript theme={null}
import axios from 'axios';

const api = axios.create({
  baseURL: 'https://api.fltr.com/v1',
  withCredentials: true,  // Include cookies
  xsrfCookieName: 'XSRF-TOKEN',
  xsrfHeaderName: 'X-XSRF-TOKEN'
});

// Make requests
await api.get('/datasets');
await api.post('/datasets', { name: 'New Dataset' });
```

## Session Management

### Check Session Status

```javascript theme={null}
async function checkSession() {
  try {
    const response = await fetch('https://api.fltr.com/v1/auth/session', {
      credentials: 'include'
    });

    if (response.ok) {
      const session = await response.json();
      return {
        authenticated: true,
        user: session.user,
        expiresAt: session.expires_at
      };
    }
  } catch (error) {
    return { authenticated: false };
  }
}
```

### Extend Session

Sessions automatically extend on each request. To manually extend:

```javascript theme={null}
await fetch('https://api.fltr.com/v1/auth/session/refresh', {
  method: 'POST',
  credentials: 'include'
});
```

### Logout

```javascript theme={null}
async function logout() {
  await fetch('https://api.fltr.com/v1/auth/logout', {
    method: 'POST',
    credentials: 'include'
  });

  // Redirect to home page
  window.location.href = '/';
}
```

## Security Best Practices

### Cookie Security

FLTR sets secure cookie attributes:

```
Set-Cookie: fltr_session=abc123;
  HttpOnly;           // Prevent JavaScript access
  Secure;             // HTTPS only
  SameSite=Lax;       // CSRF protection
  Max-Age=86400;      // 24 hour expiry
  Path=/;             // Available to all paths
```

### Frontend Security

**Do:**

* ✅ Use `credentials: 'include'` for all API requests
* ✅ Implement CSRF protection
* ✅ Use HTTPS in production
* ✅ Validate session before sensitive operations
* ✅ Implement logout on idle timeout

**Don't:**

* ❌ Store session data in localStorage
* ❌ Access cookies from JavaScript
* ❌ Make API calls without CSRF tokens
* ❌ Trust client-side session checks alone

### Backend Security

**Do:**

* ✅ Use httpOnly cookies
* ✅ Set SameSite=Lax or Strict
* ✅ Implement session expiry
* ✅ Validate CSRF tokens
* ✅ Use secure session stores (Redis)

**Don't:**

* ❌ Store sessions in memory (doesn't scale)
* ❌ Use predictable session IDs
* ❌ Send session cookies over HTTP
* ❌ Trust client-provided session data

## Error Handling

### 401 Unauthorized

Session expired or invalid:

```javascript theme={null}
fetch('https://api.fltr.com/v1/datasets', {
  credentials: 'include'
})
.then(response => {
  if (response.status === 401) {
    // Session expired - redirect to login
    window.location.href = '/login';
  }
  return response.json();
})
```

### 403 Forbidden

CSRF token invalid:

```javascript theme={null}
if (response.status === 403) {
  const error = await response.json();

  if (error.code === 'csrf_token_invalid') {
    // Retry request with fresh CSRF token
    location.reload();
  }
}
```

## Rate Limiting

Session authentication provides 15,000 requests/hour - the same as OAuth.

Check rate limit status:

```javascript theme={null}
const response = await fetch('https://api.fltr.com/v1/datasets', {
  credentials: 'include'
});

const rateLimit = {
  limit: response.headers.get('X-RateLimit-Limit'),
  remaining: response.headers.get('X-RateLimit-Remaining'),
  reset: response.headers.get('X-RateLimit-Reset')
};

console.log(`${rateLimit.remaining}/${rateLimit.limit} requests remaining`);
```

## Complete Examples

### Next.js App Router

```typescript theme={null}
// app/api/datasets/route.ts
import { cookies } from 'next/headers';

export async function GET() {
  const cookieStore = cookies();
  const sessionCookie = cookieStore.get('fltr_session');

  if (!sessionCookie) {
    return Response.json({ error: 'Not authenticated' }, { status: 401 });
  }

  const response = await fetch('https://api.fltr.com/v1/datasets', {
    headers: {
      'Cookie': `fltr_session=${sessionCookie.value}`
    }
  });

  const data = await response.json();
  return Response.json(data);
}

// app/datasets/page.tsx
'use client';

export default function DatasetsPage() {
  const [datasets, setDatasets] = useState([]);

  useEffect(() => {
    fetch('/api/datasets')
      .then(res => res.json())
      .then(data => setDatasets(data.datasets));
  }, []);

  return (
    <div>
      <h1>Datasets</h1>
      <ul>
        {datasets.map(dataset => (
          <li key={dataset.id}>{dataset.name}</li>
        ))}
      </ul>
    </div>
  );
}
```

### Vue.js 3

```vue theme={null}
<template>
  <div>
    <div v-if="!authenticated">
      <button @click="login">Login</button>
    </div>

    <div v-else>
      <button @click="logout">Logout</button>
      <ul>
        <li v-for="dataset in datasets" :key="dataset.id">
          {{ dataset.name }}
        </li>
      </ul>
    </div>
  </div>
</template>

<script setup>
import { ref, onMounted } from 'vue';

const authenticated = ref(false);
const datasets = ref([]);

async function checkAuth() {
  try {
    const response = await fetch('https://api.fltr.com/v1/auth/session', {
      credentials: 'include'
    });

    if (response.ok) {
      authenticated.value = true;
      loadDatasets();
    }
  } catch (error) {
    console.error('Not authenticated');
  }
}

async function loadDatasets() {
  const response = await fetch('https://api.fltr.com/v1/datasets', {
    credentials: 'include'
  });

  const data = await response.json();
  datasets.value = data.datasets;
}

function login() {
  const redirectUri = encodeURIComponent(window.location.href);
  window.location.href = `https://www.tryfltr.com/login?redirect_uri=${redirectUri}`;
}

async function logout() {
  await fetch('https://api.fltr.com/v1/auth/logout', {
    method: 'POST',
    credentials: 'include'
  });

  authenticated.value = false;
  datasets.value = [];
}

onMounted(checkAuth);
</script>
```

## Troubleshooting

### Cookies Not Being Set

**Cause:** CORS configuration issue

**Solution:**

1. Ensure `credentials: 'include'` is set
2. Add your domain to allowed origins in FLTR settings
3. Use HTTPS in production (required for secure cookies)

### CSRF Token Errors

**Cause:** Missing or invalid CSRF token

**Solution:**

```javascript theme={null}
// Ensure X-XSRF-TOKEN header is sent
headers: {
  'X-XSRF-TOKEN': getCsrfToken()
}
```

### Session Expires Too Quickly

**Cause:** No activity extending session

**Solution:** Make a lightweight request periodically:

```javascript theme={null}
// Extend session every 10 minutes
setInterval(async () => {
  await fetch('https://api.fltr.com/v1/auth/session/ping', {
    credentials: 'include'
  });
}, 10 * 60 * 1000);
```

## Next Steps

<CardGroup cols={2}>
  <Card title="API Keys" icon="key" href="/authentication/api-keys">
    Compare with API key authentication
  </Card>

  <Card title="OAuth" icon="shield" href="/authentication/oauth">
    When to use OAuth instead
  </Card>

  <Card title="CORS Guide" icon="globe" href="/support/cors">
    Configure CORS for your domain
  </Card>

  <Card title="Security" icon="lock" href="/support/security">
    Security best practices
  </Card>
</CardGroup>
