RaisFastRaisFast
Full-Stack Development

Auth Integration

Implement login, signup, protected routes, and token refresh in your frontend app.

How Auth Works

RaisFast uses JWT with short-lived access tokens + long-lived refresh tokens:

  1. User logs in with email/password → receives access_token (15 min) + refresh_token (7 days)
  2. Frontend stores tokens and sends access_token in the Authorization header
  3. When access_token expires, use refresh_token to get a new pair
  4. Refresh tokens are stored in the database — you can revoke them

Login Flow

import { client } from "@/lib/client";
import { useState } from "react";

function LoginPage({ onLogin }) {
  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");

  async function handleSubmit(e) {
    e.preventDefault();
    const result = await client.auth.login({ email, password });
    localStorage.setItem("access_token", result.access_token);
    localStorage.setItem("refresh_token", result.refresh_token);
    client.setToken(result.access_token);
    onLogin(result.user);
  }

  return (
    <form onSubmit={handleSubmit}>
      <input
        type="email"
        value={email}
        onChange={(e) => setEmail(e.target.value)}
        placeholder="Email"
      />
      <input
        type="password"
        value={password}
        onChange={(e) => setPassword(e.target.value)}
        placeholder="Password"
      />
      <button type="submit">Login</button>
    </form>
  );
}
<script setup>
import { ref } from "vue";
import { client } from "@/lib/client";

const emit = defineEmits(["login"]);
const email = ref("");
const password = ref("");

async function handleLogin() {
  const result = await client.auth.login({
    email: email.value,
    password: password.value,
  });
  localStorage.setItem("access_token", result.access_token);
  localStorage.setItem("refresh_token", result.refresh_token);
  client.setToken(result.access_token);
  emit("login", result.user);
}
</script>

<template>
  <form @submit.prevent="handleLogin">
    <input v-model="email" type="email" placeholder="Email" />
    <input v-model="password" type="password" placeholder="Password" />
    <button type="submit">Login</button>
  </form>
</template>
import { RaisFast } from "@raisfast/sdk";

const client = new RaisFast({ baseUrl: "/api" });

async function login(email, password) {
  const result = await client.auth.login({ email, password });
  localStorage.setItem("access_token", result.access_token);
  localStorage.setItem("refresh_token", result.refresh_token);
  client.setToken(result.access_token);
  return result.user;
}

// Usage
document.getElementById("loginForm").addEventListener("submit", async (e) => {
  e.preventDefault();
  const user = await login(
    document.getElementById("email").value,
    document.getElementById("password").value
  );
  console.log("Logged in as", user.username);
});

Token Refresh

Access tokens expire in 15 minutes. Handle refresh automatically:

import { client } from "./client";

let refreshPromise: Promise<void> | null = null;

export async function getValidToken(): Promise<string> {
  const token = localStorage.getItem("access_token");
  if (token) {
    const payload = JSON.parse(atob(token.split(".")[1]));
    if (payload.exp * 1000 > Date.now()) {
      return token;
    }
  }

  if (!refreshPromise) {
    refreshPromise = (async () => {
      const refreshToken = localStorage.getItem("refresh_token");
      const result = await client.auth.refresh(refreshToken!);
      localStorage.setItem("access_token", result.access_token);
      localStorage.setItem("refresh_token", result.refresh_token);
      client.setToken(result.access_token);
      refreshPromise = null;
    })();
  }

  await refreshPromise;
  return localStorage.getItem("access_token")!;
}

Protected Routes (React Example)

import { useState, useEffect } from "react";
import { client } from "@/lib/client";
import { getValidToken } from "@/lib/auth";

function ProtectedRoute({ children }) {
  const [user, setUser] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    const token = localStorage.getItem("access_token");
    if (!token) {
      setLoading(false);
      return;
    }
    client.setToken(token);
    client.auth.me().then(setUser).catch(() => {
      localStorage.removeItem("access_token");
    }).finally(() => setLoading(false));
  }, []);

  if (loading) return <div>Loading...</div>;
  if (!user) return <Navigate to="/login" />;

  return children;
}

Logout

async function logout() {
  const refreshToken = localStorage.getItem("refresh_token");
  if (refreshToken) {
    await client.auth.logout(refreshToken);
  }
  localStorage.removeItem("access_token");
  localStorage.removeItem("refresh_token");
  client.setToken("");
}

Registration

const user = await client.auth.register({
  username: "newuser",
  email: "user@example.com",
  password: "MyStr0ngP@ss",
});

Next Step

With auth in place, let's connect data and CRUD operations.

On this page