Skip to content

Authentication Setup

AV API supports multiple authentication methods:

  • Email/Password (Traditional signup & login)
  • Google OAuth 2.0 (Social login)
  • Facebook OAuth 2.0 (Social login)
  • Microsoft OAuth 2.0 (Social login)

All methods return JWT tokens for API authorization.

Authentication Flow

User (Frontend)
    ├─ Email/Password Signup: POST /api/signup/
    ├─ Email/Password Login: POST /api/login/
    ├─ Google OAuth: POST /api/auth/google/
    ├─ Facebook OAuth: POST /api/auth/facebook/
    └─ Microsoft OAuth: POST /api/auth/microsoft/
Backend validates credentials/token
Returns JWT tokens + User profile
Frontend uses JWT for all API requests

Option 1: Email/Password Authentication

The simplest authentication method - create an account and login with email and password.

Sign Up

Endpoint: POST /api/signup/

Request:

{
  "email": "[email protected]",
  "password": "MySecurePassword123",
  "password_confirm": "MySecurePassword123",
  "first_name": "John",
  "last_name": "Doe"
}

Requirements: - Email must be unique - Password must be at least 8 characters long - Passwords must match

Response (201 Created):

{
  "access": "eyJ0eXAiOiJKV1QiLCJhbGc...",
  "refresh": "eyJ0eXAiOiJKV1QiLCJhbGc...",
  "user": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "email": "[email protected]",
    "first_name": "John",
    "last_name": "Doe",
    "date_joined": "2025-10-29T12:00:00Z"
  }
}

Login

Endpoint: POST /api/login/

Request:

{
  "email": "[email protected]",
  "password": "MySecurePassword123"
}

Response (200 OK):

{
  "access": "eyJ0eXAiOiJKV1QiLCJhbGc...",
  "refresh": "eyJ0eXAiOiJKV1QiLCJhbGc...",
  "user": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "email": "[email protected]",
    "first_name": "John",
    "last_name": "Doe",
    "date_joined": "2025-10-29T12:00:00Z"
  }
}

JavaScript Example

// Signup
async function signup(email, password, firstName, lastName) {
  const response = await fetch('http://localhost:8000/api/signup/', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      email,
      password,
      password_confirm: password,
      first_name: firstName,
      last_name: lastName
    })
  });

  if (response.ok) {
    const data = await response.json();
    localStorage.setItem('accessToken', data.access);
    localStorage.setItem('refreshToken', data.refresh);
    return data.user;
  }
  throw new Error('Signup failed');
}

// Login
async function login(email, password) {
  const response = await fetch('http://localhost:8000/api/login/', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ email, password })
  });

  if (response.ok) {
    const data = await response.json();
    localStorage.setItem('accessToken', data.access);
    localStorage.setItem('refreshToken', data.refresh);
    return data.user;
  }
  throw new Error('Login failed');
}

Option 2: Google OAuth

Get Google OAuth Token (Frontend)

Use Google Sign-In on your frontend to get a Google OAuth token.

Using Google Sign-In Library

<!-- Add Google Sign-In script -->
<script src="https://accounts.google.com/gsi/client" async defer></script>
// Initialize Google Sign-In
google.accounts.id.initialize({
  client_id: 'YOUR_CLIENT_ID.apps.googleusercontent.com',
  callback: handleGoogleResponse
});

// Show sign-in button
google.accounts.id.renderButton(
  document.getElementById('googleSignInButton'),
  { theme: 'outline', size: 'large' }
);

// Handle response
function handleGoogleResponse(response) {
  const googleToken = response.credential;
  // Now exchange for JWT tokens (Step 2)
  authenticateWithBackend(googleToken);
}

Exchange Google Token for JWT Tokens

Send the Google token to the backend to get JWT tokens.

Endpoint: POST /api/auth/google/

Request:

{
  "access_token": "GOOGLE_OAUTH_TOKEN"
}

Response

{
  "access": "eyJ0eXAiOiJKV1QiLCJhbGc...",
  "refresh": "eyJ0eXAiOiJKV1QiLCJhbGc...",
  "user": {
    "id": 1,
    "email": "[email protected]",
    "first_name": "John",
    "last_name": "Doe"
  }
}

JavaScript Example

async function authenticateWithBackend(googleToken) {
  const response = await fetch('http://localhost:8000/api/auth/google/', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      access_token: googleToken
    })
  });

  if (response.ok) {
    const data = await response.json();

    // Store tokens
    const accessToken = data.access;
    const refreshToken = data.refresh;
    const user = data.user;

    console.log('Authenticated as:', user.email);

    // Store in memory (recommended)
    window.authTokens = {
      access: accessToken,
      refresh: refreshToken
    };
  }
}
async function authenticateWithBackend(googleToken) {
  try {
    const response = await axios.post('http://localhost:8000/api/auth/google/', {
      access_token: googleToken
    });

    const { access, refresh, user } = response.data;

    console.log('Authenticated as:', user.email);

    // Store tokens
    window.authTokens = {
      access: access,
      refresh: refresh
    };
  } catch (error) {
    console.error('Authentication failed:', error);
  }
}

Option 3: Facebook OAuth

Endpoint: POST /api/auth/facebook/

Authenticate using Facebook OAuth token.

Request:

{
  "access_token": "FACEBOOK_OAUTH_TOKEN"
}

Response:

{
  "access": "eyJ0eXAiOiJKV1QiLCJhbGc...",
  "refresh": "eyJ0eXAiOiJKV1QiLCJhbGc...",
  "user": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "email": "[email protected]",
    "first_name": "John",
    "last_name": "Doe",
    "date_joined": "2025-10-29T12:00:00Z"
  }
}

JavaScript Example:

// Using Facebook SDK
FB.login(function(response) {
  if (response.authResponse) {
    const accessToken = response.authResponse.accessToken;

    fetch('http://localhost:8000/api/auth/facebook/', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ access_token: accessToken })
    })
    .then(res => res.json())
    .then(data => {
      localStorage.setItem('accessToken', data.access);
      localStorage.setItem('refreshToken', data.refresh);
      console.log('Authenticated as:', data.user.email);
    });
  }
}, {scope: 'public_profile,email'});

Option 4: Microsoft OAuth

Endpoint: POST /api/auth/microsoft/

Authenticate using Microsoft OAuth token.

Request:

{
  "access_token": "MICROSOFT_OAUTH_TOKEN"
}

Response:

{
  "access": "eyJ0eXAiOiJKV1QiLCJhbGc...",
  "refresh": "eyJ0eXAiOiJKV1QiLCJhbGc...",
  "user": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "email": "[email protected]",
    "first_name": "John",
    "last_name": "Doe",
    "date_joined": "2025-10-29T12:00:00Z"
  }
}

JavaScript Example:

// Using Microsoft MSAL
const msalConfig = {
  auth: {
    clientId: 'YOUR_MICROSOFT_CLIENT_ID'
  }
};

const msalInstance = new msal.PublicClientApplication(msalConfig);

msalInstance.loginPopup({
  scopes: ['User.Read']
}).then(response => {
  const accessToken = response.accessToken;

  fetch('http://localhost:8000/api/auth/microsoft/', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ access_token: accessToken })
  })
  .then(res => res.json())
  .then(data => {
    localStorage.setItem('accessToken', data.access);
    localStorage.setItem('refreshToken', data.refresh);
    console.log('Authenticated as:', data.user.email);
  });
}).catch(error => console.error('Login failed:', error));

Using Access Token for API Requests

Include the access token in the Authorization header for all API requests.

Request Example

GET /api/me/
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGc...

JavaScript Example

async function makeAPIRequest(endpoint) {
  const accessToken = window.authTokens.access;

  const response = await fetch(`http://localhost:8000${endpoint}`, {
    headers: {
      'Authorization': `Bearer ${accessToken}`,
      'Content-Type': 'application/json'
    }
  });

  if (response.ok) {
    return await response.json();
  } else if (response.status === 401) {
    // Token expired - refresh it (see Token Management)
    console.log('Token expired');
  }
}

// Example: Get user profile
async function getUserProfile() {
  const profile = await makeAPIRequest('/api/me/');
  console.log(profile);
}

Token Information

Token Lifetime Purpose
Access Token 60 minutes API requests
Refresh Token 1 day Get new access token

Token Expiration

Access tokens expire after 60 minutes. See Token Management for how to handle expiration.

Security Best Practices

✅ DO:

  • Store tokens in memory (JavaScript variables)
  • Use HTTPS in production
  • Clear tokens on logout
  • Handle token expiration

❌ DON'T:

  • Store tokens in localStorage (XSS risk)
  • Log tokens to console in production
  • Expose tokens in URLs
  • Share tokens between users

Testing with cURL

# 1. Get Google OAuth token (use Google OAuth Playground or your frontend)
GOOGLE_TOKEN="your_google_oauth_token"

# 2. Exchange for JWT tokens
curl -X POST http://localhost:8000/api/auth/google/ \
  -H "Content-Type: application/json" \
  -d "{\"access_token\":\"$GOOGLE_TOKEN\"}"

# Response will contain access and refresh tokens

Next Steps


Email Verification

Email verification is optional by default in development mode.

Configuration

Setting Value Meaning
ACCOUNT_EMAIL_VERIFICATION optional Users can verify email but it's not required
Email Verification ❌ Not enforced Sign up works immediately without email confirmation
Good for Development Faster testing, no email required

In Production

For production, consider changing to enforce email verification:

# In core/settings.py
ACCOUNT_EMAIL_VERIFICATION = "mandatory"  # Require email verification before login
# or
ACCOUNT_EMAIL_VERIFICATION = "optional"  # Suggest email verification

Security Best Practices

✅ DO:

  • Store access tokens in memory only (React Context recommended)
  • Store refresh token securely (httpOnly cookies or secure localStorage)
  • Use HTTPS in production
  • Clear tokens on logout
  • Handle token expiration with automatic refresh
  • Validate refresh token on every app load
  • Set secure CORS origins

❌ DON'T:

  • Store access tokens in localStorage (XSS risk!)
  • Log tokens to console in production
  • Expose tokens in URLs
  • Share tokens between users
  • Use weak passwords (< 8 characters)
  • Store OAuth app secrets in frontend code
  • Skip HTTPS in production
  • Store sensitive data in JWT payload

Token Storage Recommendations

Best Practice (Recommended):

// Store in memory/React Context
const [authTokens, setAuthTokens] = useState({ access: null, refresh: null });
// Lost on page refresh - implement persistent login with secure refresh

Implementation Pattern:

// On app load, check if refresh token exists
useEffect(() => {
  const refreshToken = localStorage.getItem('refreshToken');
  if (refreshToken && !authTokens.access) {
    // Refresh tokens to restore session
    refreshAccessToken();
  }
}, []);

Avoid:

// DON'T store access tokens in localStorage
localStorage.setItem('accessToken', token); // ❌ XSS vulnerability!


Logout

Always clear tokens when user logs out:

function logout() {
  // Clear all tokens
  localStorage.removeItem('refreshToken');
  setAuthTokens({ access: null, refresh: null });
  setUser(null);

  // Redirect to login
  window.location.href = '/login';
}

Setting Up OAuth Credentials

Google OAuth

  1. Go to Google Cloud Console
  2. Create a new project
  3. Enable Google+ API
  4. Create OAuth 2.0 credentials (Web application)
  5. Add authorized redirect URI: http://localhost:3000/auth/callback/google
  6. Copy Client ID and Client Secret to .env:
    GOOGLE_OAUTH_CLIENT_ID=your-client-id
    GOOGLE_OAUTH_CLIENT_SECRET=your-client-secret
    

Facebook OAuth

  1. Go to Facebook Developers
  2. Create a new app → Facebook Login
  3. In Settings > Basic, get App ID and App Secret
  4. In Settings > Basic, add Valid OAuth Redirect URIs:
  5. http://localhost:3000/auth/callback/facebook
  6. Copy credentials to .env:
    FACEBOOK_APP_ID=your-app-id
    FACEBOOK_APP_SECRET=your-app-secret
    

Microsoft OAuth

  1. Go to Azure Portal
  2. Create App Registration
  3. In Certificates & secrets, create Client Secret
  4. In Authentication, add Redirect URI:
  5. http://localhost:3000/auth/callback/microsoft
  6. Copy Client ID and Client Secret to .env:
    MICROSOFT_APP_ID=your-client-id
    MICROSOFT_APP_SECRET=your-client-secret
    

Complete Authentication Flow Diagram

┌─────────────────────────────────────────────────────────────────┐
│                        Frontend (React)                         │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  User clicks "Sign Up"                                         │
│         ↓                                                       │
│  Fills email, password → POST /api/signup/                     │
│         ↓                                                       │
│  Response: { access, refresh, user }                           │
│         ↓                                                       │
│  Store: access in memory, refresh in secure storage            │
│         ↓                                                       │
│  Display: Welcome, {user.first_name}!                          │
│         ↓                                                       │
│  Make API requests: Authorization: Bearer {access}             │
│         ↓                                                       │
│  After 60 minutes, access token expires (401 error)            │
│         ↓                                                       │
│  Auto-refresh: POST /api/token/refresh/ with {refresh}         │
│         ↓                                                       │
│  Get new access token → Continue using API                     │
│         ↓                                                       │
│  After 1 day, refresh token expires                            │
│         ↓                                                       │
│  Prompt: "Session expired. Please sign in again."              │
│         ↓                                                       │
│  Clear tokens & redirect to login                              │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

Common Issues & Solutions

Issue: "Invalid email or password"

  • ✅ Check email spelling
  • ✅ Verify password is correct
  • ✅ Ensure user account exists

Issue: "A user with this email already exists"

  • ✅ Use login endpoint instead of signup
  • ✅ Use different email for new account
  • ✅ Request password reset

Issue: "Given token not valid for any token type"

  • ✅ Access token has expired → use refresh token
  • ✅ Refresh token is invalid → user must re-authenticate

Issue: "OAuth token invalid"

  • ✅ Google/Facebook/Microsoft token expired → get fresh token
  • ✅ Wrong provider token → use correct provider endpoint
  • ✅ Token revoked in OAuth provider settings

Testing Authentication

With cURL

# 1. Sign up
curl -X POST http://localhost:8000/api/signup/ \
  -H "Content-Type: application/json" \
  -d '{
    "email": "[email protected]",
    "password": "TestPassword123",
    "password_confirm": "TestPassword123",
    "first_name": "Test",
    "last_name": "User"
  }' | jq

# 2. Login
curl -X POST http://localhost:8000/api/login/ \
  -H "Content-Type: application/json" \
  -d '{
    "email": "[email protected]",
    "password": "TestPassword123"
  }' | jq

# 3. Use access token
ACCESS_TOKEN=$(curl -s -X POST http://localhost:8000/api/login/ \
  -H "Content-Type: application/json" \
  -d '{"email":"[email protected]","password":"TestPassword123"}' | jq -r '.access')

curl -H "Authorization: Bearer $ACCESS_TOKEN" \
  http://localhost:8000/api/me/ | jq

# 4. Refresh token
REFRESH_TOKEN=$(curl -s -X POST http://localhost:8000/api/login/ \
  -H "Content-Type: application/json" \
  -d '{"email":"[email protected]","password":"TestPassword123"}' | jq -r '.refresh')

curl -X POST http://localhost:8000/api/token/refresh/ \
  -H "Content-Type: application/json" \
  -d "{\"refresh\":\"$REFRESH_TOKEN\"}" | jq

Environment Configuration

See .env.example for all required environment variables:

# Copy and customize
cp .env.example .env

# Edit .env and add your OAuth credentials
GOOGLE_OAUTH_CLIENT_ID=...
GOOGLE_OAUTH_CLIENT_SECRET=...
FACEBOOK_APP_ID=...
FACEBOOK_APP_SECRET=...
MICROSOFT_APP_ID=...
MICROSOFT_APP_SECRET=...