Skip to content

3lvin-Kc/authbase-react

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

12 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

authbase-react : This is an early project. The goal is correctness first, adoption later.

A dead simple auth state manager for React. No magic, no suprises. This library is intentionally small. Many teams may prefer to inline similar logic instead of adding a dependency — this project exists to make that logic explicit and correct.

What is this?

This is just a state machine that holds your auth tokens and user data. That's it. It doesn't authenticate anyone, it doesn't talk to Supabase or Firebase or whatever. It just manages the logged-in/logged-out state on the frontend.

Think of it like useState but spacifically for auth stuff.

Why does this exist?

Because every time I start a new React project, I end up writing the same auth boilerplate. Login form, logout button, protect some routes, store tokens in localStorage... you know the drill.

I got tired of copy-pasting this code around, so I made a library. Maybe you'll find it usefull too.

What it does

  • Manages login/logout state
  • Stores tokens in localStorage (or wherever you want)
  • Gives you hooks to check if someone's logged in
  • Protects routes that need authentication
  • Handles token refresh when you tell it to

What it does NOT do

  • No OAuth flows (build that yourself)
  • No cookie auth (we use tokens)
  • No automatic background token refresh (you call refresh when needed)
  • No fancy UI components
  • No backend (you need to build your own API)

Install

npm install authbase-react

Basic setup

Wrap your app:

import { AuthProvider } from 'authbase-react';

const authConfig = {
  endpoints: {
    login: 'https://your-api.com/auth/login',
    refresh: 'https://your-api.com/auth/refresh',
    logout: 'https://your-api.com/auth/logout',
  },
};

function App() {
  return (
    <AuthProvider config={authConfig}>
      <YourApp />
    </AuthProvider>
  );
}

That's it. Now you can use the hooks anywhere. Pretty simple right?

Make a login form

import { useAuth } from 'authbase-react';

function LoginPage() {
  const { signIn, isLoading, error } = useAuth();
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');

  const handleSubmit = async (e) => {
    e.preventDefault();
    try {
      await signIn(email, password);
      // user is now logged in baby
    } catch (err) {
      // error is in the error state, you know what to do?
    }
  };

  return (
    <form onSubmit={handleSubmit}>
      <input 
        type="email" 
        value={email} 
        onChange={(e) => setEmail(e.target.value)} 
      />
      <input 
        type="password" 
        value={password} 
        onChange={(e) => setPassword(e.target.value)} 
      />
      <button disabled={isLoading}>
        {isLoading ? 'Loading...' : 'Login'}
      </button>
      {error && <p>{error.message}</p>}
    </form>
  );
}

Protect routes

import { RequireAuth } from 'authbase-react';

function Dashboard() {
  return (
    <RequireAuth redirectTo="/login">
      <YourDashboard />
    </RequireAuth>
  );
}

If the user isn't logged in, they get redirected to /login. Simple as that.

Check if someone's logged in

import { useIsAuthenticated } from 'authbase-react';

function Navigation() {
  const isLoggedIn = useIsAuthenticated();

  return (
    <nav>
      {isLoggedIn ? (
        <a href="/dashboard">Dashboard</a>
      ) : (
        <a href="/login">Login</a>
      )}
    </nav>
  );
}

Get user data

import { useUser } from 'authbase-react';

function Profile() {
  const user = useUser();

  if (!user) return null;

  return <div>Hey {user.name}!</div>;
}

Logout

import { useAuth } from 'authbase-react';

function LogoutButton() {
  const { signOut } = useAuth();

  return <button onClick={signOut}>Logout</button>;
}

Refresh tokens manually

import { useAuth } from 'authbase-react';

function SomeComponent() {
  const { refresh, accessToken } = useAuth();

  const callAPI = async () => {
    let response = await fetch('/api/data', {
      headers: { Authorization: `Bearer ${accessToken}` }
    });

    if (response.status === 401) {
      // token expired, fuckin' refresh it
      await refresh();
      // now let it try again with the new token folks....
    }
  };
}

Backend contract

Your backend needs to match this:

Login endpoint:

POST /auth/login
Body: { identifier: string, secret: string }
Response: {
  access_token: string,
  refresh_token?: string,
  user: object
}

Failure cases:

  • 401/403 for invalid credentials (will surface as an error in the auth state)
  • 4xx/5xx for API issues (will surface as an error in the auth state)

Refresh endpoint (optional):

POST /auth/refresh
Headers: Authorization: Bearer {refresh_token}
Response: {
  access_token: string
}

Failure cases:

  • 401/403 for expired/invalid refresh token (will transition to unauthenticated)
  • 4xx/5xx for API issues (will surface as an error in the auth state)

Logout endpoint (optional):

POST /auth/logout
Headers: Authorization: Bearer {access_token}
Response: 204

Failure cases:

  • 4xx/5xx errors are captured but local auth state still clears

That's all we support right now. If your API looks different, this library won't work for you (yet). Sorry bout that.

Custom storage

By default we use localStorage. Want sessionStorage instead? Easy peasy.

const authConfig = {
  endpoints: { /* ... */ },
  storage: window.sessionStorage,
};

Available hooks

useAuth() - Everything

const {
  signIn,        // (identifier, secret) => Promise<void>
  signOut,       // () => Promise<void>
  refresh,       // () => Promise<void>
  user,          // object | null
  accessToken,   // string | null
  isAuthenticated, // boolean
  isLoading,     // boolean
  error,         // Error | null
} = useAuth();

useUser() - Just the user object

useIsAuthenticated() - Just a boolean, yep

State machine overview

Authbase-react is intentionally deterministic. These are the only possible states and transitions:

States

  • idle → initial state before storage is checked
  • loading → a login/logout/refresh/init is in progress
  • authenticated → user + access token are present
  • unauthenticated → no valid session
  • error → an operation failed (error is stored in state)

Common transitions

  • idleloadingauthenticated | unauthenticated
  • unauthenticatedloadingauthenticated (login success)
  • authenticatedloadingunauthenticated (logout)
  • authenticatedloadingauthenticated | unauthenticated (refresh)

Philosophy

This library is intentionally boring. There's no clever tricks, no abstractions, no "magic". It's just a state machine that stores some data. Boring is good sometimes.

We don't do automatic token refresh because that's complicated and every app needs it differently. Just call refresh() when you need it. Simple.

We don't support OAuth because that's a whole different beast. Build your OAuth flow, then use this library to store the result. Makes sense right?

We don't have fancy loading states or retry logic because your app probably needs custom handling anyway. You know your app better than we do.

When NOT to use this

  • You need OAuth social login (use next-auth or similar, seriously)

  • You use cookie-based auth (this is for tokens only)

  • You need SSR/Next.js support (maybe later)

  • You want something that "just works" with zero config (this needs backend work, sorry)

Sec - notes :

authbase-react does not attempt to provide the most secure possible browser auth model.

Storing access and refresh tokens in JavaScript-accessible storage (localStorage / sessionStorage) is vulnerable to XSS. For high-security apps, prefer:

httpOnly cookie-based refresh tokens

backend-managed sessions

This library is best suited for apps where those trade-offs are acceptable.

Contributing

Found a bug? Open an issue. Want to add something? Check out CONTRIBUTING.md for the full contribution guide.

License

MIT - do whatever you want with it, seriously!!!!!!!!!

Questions?

Open an issue and I'll try to help. No guarantees but I'll do my best.

About

A dead simple auth state manager for React. No magic, no suprises.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors