Skip to main content

SecureBite

SecureBite is a Django package that provides secure, cookie-based authentication and session management using JWT tokens. It integrates seamlessly with Django REST Framework (DRF) and SimpleJWT, offering a simple and secure authentication experience for SPAs and mobile apps.

It supports traditional username/password login, OAuth2 providers (Google, GitHub, etc.), automatic token refreshing, and logout handling — all with HTTP-only cookies for maximum security.


Features

  • Cookie-Based JWT Authentication – JWT tokens are stored in HTTP-only cookies to prevent XSS token theft.
  • Automatic Token Refreshing – Middleware refreshes access tokens before expiry.
  • Logout Support – Securely clears authentication cookies.
  • OAuth2 Login Support – Optional integration with external providers like Google, GitHub, etc.
  • User Serialization – Easily customize what user data is returned in /auth/me/.
  • Simple Integration – Works out of the box with minimal setup.

Installation

  1. Install required dependencies
pip install django djangorestframework djangorestframework-simplejwt djangorestframework-simplejwt[token_blacklist] secure_bite
  1. Add to settings.py
from datetime import timedelta

INSTALLED_APPS = [
    'secure_bite',
    'rest_framework',
    'rest_framework_simplejwt',
    'rest_framework_simplejwt.token_blacklist',
    'corsheaders',
    ...
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'corsheaders.middleware.CorsMiddleware',
    ...
    'secure_bite.middleware.RefreshTokenMiddleware',  # SecureBite middleware
]

REST_FRAMEWORK = {
    "DEFAULT_AUTHENTICATION_CLASSES": [
        "secure_bite.authentication.JWTAuthCookieAuthentication",
    ],
}

SIMPLE_JWT = {
    "ACCESS_TOKEN_LIFETIME": timedelta(minutes=15),
    "REFRESH_TOKEN_LIFETIME": timedelta(days=7),
    "ROTATE_REFRESH_TOKENS": True,
    "BLACKLIST_AFTER_ROTATION": True,
}

JWT_AUTH_COOKIE_SETTINGS = {
    "AUTH_COOKIE": "authToken",                 # Access token cookie name
    "REFRESH_COOKIE": "refreshToken",           # Refresh token cookie name
    "AUTH_COOKIE_HTTP_ONLY": True,              # Prevents JavaScript access
    "AUTH_COOKIE_SECURE": False,                # True in production (HTTPS)
    "AUTH_COOKIE_SAMESITE": "Lax",
    "USER_SERIALIZER": "secure_bite.serializers.UserSerializer",
}

URL Configuration

In your root urls.py:

from django.urls import path, include

urlpatterns = [
    path("auth/", include("secure_bite.urls", namespace="secure_bite")),
]

Usage

1. Login

POST /auth/login/

Authenticates a user and sets authToken and refreshToken cookies.

Request

{
  "email": "user@example.com",
  "password": "your_password"
}

Response

{
  "message": "Login successful"
}

2. OAuth2 Login

GET /auth/oauth_start//example.com/

Redirects the user to the OAuth provider (e.g., Google). After authentication, the user is redirected back with valid cookies set.

Supported providers (example):

  • /auth/oauth_start/google/example.com/
  • /auth/oauth_start/github/example.com/

3. Logout

POST /auth/logout/

Clears authentication cookies.

Response

{
  "message": "Logged out"
}

4. Get Current User

GET /auth/me/

Returns user details based on the active access token.

Response

{
  "id": 1,
  "email": "user@example.com"
}

5. Automatic Token Refresh

The middleware automatically refreshes tokens near expiry. No frontend logic is required — tokens are renewed silently via cookies.


Example React Integration

Below is a minimal React setup using Context API and Axios to work with SecureBite’s endpoints.


1. UserContext.js

import React, { createContext, useContext, useEffect, useState } from "react";
import axios from "axios";

const UserContext = createContext();

export const UserProvider = ({ children }) => {
  const [user, setUser] = useState(null);
  const [loading, setLoading] = useState(true);

  const fetchUser = async () => {
    try {
      const res = await axios.get("/auth/me/", { withCredentials: true });
      setUser(res.data);
    } catch {
      setUser(null);
    } finally {
      setLoading(false);
    }
  };

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

  const login = async (email, password) => {
    await axios.post("/auth/login/", { email, password }, { withCredentials: true });
    await fetchUser();
  };

  const logout = async () => {
    await axios.post("/auth/logout/", {}, { withCredentials: true });
    setUser(null);
  };

  return (
    <UserContext.Provider value={{ user, loading, login, logout }}>
      {loading ? <div>Loading...</div> : children}
    </UserContext.Provider>
  );
};

export const useUser = () => useContext(UserContext);

2. Login.js

import React, { useState } from "react";
import { useUser } from "./UserContext";

const Login = () => {
  const { login } = useUser();
  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");

  const handleSubmit = async (e) => {
    e.preventDefault();
    await login(email, password);
  };

  return (
    <form onSubmit={handleSubmit}>
      <input type="email" value={email} onChange={(e) => setEmail(e.target.value)} placeholder="Email" required />
      <input type="password" value={password} onChange={(e) => setPassword(e.target.value)} placeholder="Password" required />
      <button type="submit">Login</button>
    </form>
  );
};

export default Login;

3. Profile.js

import React from "react";
import { useUser } from "./UserContext";

const Profile = () => {
  const { user, logout } = useUser();

  if (!user) return <div>Not logged in</div>;

  return (
    <div>
      <h2>Welcome, {user.email}</h2>
      <button onClick={logout}>Logout</button>
    </div>
  );
};

export default Profile;

4. App Setup

import React from "react";
import { UserProvider } from "./UserContext";
import Login from "./Login";
import Profile from "./Profile";

function App() {
  return (
    <UserProvider>
      <Profile />
      <Login />
    </UserProvider>
  );
}

export default App;

OAuth2 Integration (React)

SecureBite supports OAuth2 logins (Google, GitHub, etc.). The flow is simple: redirect the user to the provider, receive a callback, and set JWT cookies.


1. Redirect to Provider

Create a React button to redirect users:

import React from "react";

const OAuthLoginButton = ({ provider }) => {
  const handleLogin = () => {
    // Redirect user to backend OAuth endpoint
    window.location.href = `/auth/oauth_start/${provider}/example.com/`;
  };

  return (
    <button onClick={handleLogin}>
      Login with {provider.charAt(0).toUpperCase() + provider.slice(1)}
    </button>
  );
};

export default OAuthLoginButton;
  • provider can be "google", "github", etc.
  • Clicking the button sends the user to the backend OAuth login page.

2. OAuth Callback Handling

After the user authenticates with the provider, they are redirected back to your frontend (configured in the OAuth provider settings). SecureBite sets the JWT cookies automatically.

You can handle the frontend state like this:

import React, { useEffect } from "react";
import { useUser } from "./UserContext";
import { useNavigate } from "react-router-dom";

const OAuthCallback = () => {
  const { fetchUser } = useUser(); // from UserContext
  const navigate = useNavigate();

  useEffect(() => {
    // Fetch the authenticated user after OAuth callback
    const fetchAndRedirect = async () => {
      await fetchUser();
      navigate("/dashboard"); // Redirect to a protected route
    };
    fetchAndRedirect();
  }, [fetchUser, navigate]);

  return <div>Logging you in...</div>;
};

export default OAuthCallback;

Flow:

  1. User clicks Login with Google → Redirected to /auth/oauth_start/google/example.com/
  2. Authenticated by Google → Redirected back to your frontend callback URL
  3. SecureBite sets JWT cookies (authToken and refreshToken)
  4. React UserContext fetches user data → App renders protected pages

3. Example Routes Setup (React Router v6)

import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
import { UserProvider } from "./UserContext";
import Login from "./Login";
import Profile from "./Profile";
import OAuthCallback from "./OAuthCallback";

function App() {
  return (
    <UserProvider>
      <Router>
        <Routes>
          <Route path="/" element={<Login />} />
          <Route path="/profile" element={<Profile />} />
          <Route path="/oauth/callback" element={<OAuthCallback />} />
        </Routes>
      </Router>
    </UserProvider>
  );
}

export default App;

4. Key Considerations

  • CORS: Ensure your Django backend allows your frontend domain. Include withCredentials: true in Axios requests.
  • HTTPS: Required in production for secure cookies.
  • React State: After OAuth callback, always fetch the user via /auth/me/ to update the frontend state.
  • Logout: Works the same as standard login; JWT cookies are cleared by /auth/logout/.

This allows React apps to handle OAuth logins without manually dealing with tokens — SecureBite manages cookies automatically.



Security Tips

  • Use HTTPS in production to protect cookies.
  • Set AUTH_COOKIE_SECURE=True for production.
  • Enable CSRF protection when using POST requests.
  • Use token_blacklist to invalidate refresh tokens when users log out.

Contributing

We welcome contributions!

  1. Fork the repository
  2. Create a new branch (git checkout -b feature-branch)
  3. Commit your changes
  4. Push and open a pull request

License

This project is licensed under the Apache License 2.0. See the LICENSE file for details.

Metadata

Release files for secure-bite 0.1.4

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for secure-bite 0.1.4
File Size Uploaded
secure_bite-0.1.4.tar.gz 19.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for secure-bite 0.1.4
File Interpreter ABI Platform
secure_bite-0.1.4-py3-none-any.whl Python 3 none any Details

Total release size: 39.2 kB

Release files / secure_bite-0.1.4.tar.gz

Download URL secure_bite-0.1.4.tar.gz
Size 19.4 kB
Tags Source
SHA-256 checksum
How to use checksums
f7dd020ce218643364ef290b8e065bdfb4e81a1f1b1cb49daf22fbc70f7d6a1e
BLAKE2b-256 checksum
How to use checksums
ce2833b0625ac7bed2c913d716250f9840785613330af42df082560099aa29a0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.10.18

Release files / secure_bite-0.1.4-py3-none-any.whl

Download URL secure_bite-0.1.4-py3-none-any.whl
Size 19.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
aa7f5c868c519a688012a4ec02c3aad54f4c1ef9243c44cc772f28af0b34fc09
BLAKE2b-256 checksum
How to use checksums
119f6149d2797c6c7aeff193eb44b23496234f422dcfdf16b0d563a4f5519156
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.10.18

Release history Release notifications | RSS feed

This release

0.1.4 This release

2 release files

0.1.3

2 release files

0.1.2

2 release files

0.1.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page