Aller au contenu

Supabase & Astro

Supabase est une alternative open source à Firebase. Elle fournit une base de données Postgres, l’authentification, des fonctions edge, des abonnements en temps réel et le stockage.

  • Un projet Supabase. Si vous n’en avez pas, vous pouvez vous inscrire gratuitement sur supabase.com et créer un nouveau projet.
  • Un projet Astro avec server-side rendering (SSR) activé.
  • Les identifiants Supabase pour votre projet. Vous pouvez les trouver dans l’onglet Paramètres > API de votre projet Supabase.
    • SUPABASE_URL : L’URL de votre projet Supabase.
    • SUPABASE_ANON_KEY : La clé anonyme de votre projet Supabase.

Ajouter les informations d’identification de Supabase

Titre de la section Ajouter les informations d’identification de Supabase

Pour ajouter vos identifiants Supabase à votre projet Astro, ajoutez ce qui suit à votre fichier .env :

.env
SUPABASE_URL=YOUR_SUPABASE_URL
SUPABASE_ANON_KEY=YOUR_SUPABASE_ANON_KEY

Maintenant, ces variables d’environnement sont disponibles dans votre projet.

Si vous souhaitez avoir IntelliSense pour vos variables d’environnement, éditez ou créez le fichier env.d.ts dans votre répertoire src/ et ajoutez ce qui suit :

src/env.d.ts
interface ImportMetaEnv {
readonly SUPABASE_URL: string
readonly SUPABASE_ANON_KEY: string
}
interface ImportMeta {
readonly env: ImportMetaEnv
}

Votre projet doit maintenant inclure ces fichiers :

  • Répertoiresrc/
    • env.d.ts
  • .env
  • astro.config.mjs
  • package.json

Pour vous connecter à Supabase, vous devez installer @supabase/supabase-js dans votre projet.

Fenêtre de terminal
npm install @supabase/supabase-js

Ensuite, créez un dossier nommé lib dans votre répertoire src/. C’est là que vous ajouterez votre client Supabase.

Dans supabase.ts, ajoutez ce qui suit pour initialiser votre client Supabase :

src/lib/supabase.ts
import { createClient } from "@supabase/supabase-js";
export const supabase = createClient(
import.meta.env.SUPABASE_URL,
import.meta.env.SUPABASE_ANON_KEY,
);

Votre projet doit maintenant inclure ces fichiers :

  • Répertoiresrc/
    • Répertoirelib/
      • supabase.ts
    • env.d.ts
  • .env
  • astro.config.mjs
  • package.json

Ajouter l’authentification avec Supabase

Titre de la section Ajouter l’authentification avec Supabase

Supabase fournit l’authentification dès le départ. Elle supporte l’authentification par email/mot de passe et l’authentification OAuth avec de nombreux fournisseurs dont GitHub, Google, et plusieurs autres.

  • Un projet Astro initialisé avec Supabase.
  • Un projet Supabase avec l’authentification email/mot de passe activée. Vous pouvez l’activer dans l’onglet Authentication > Providers de votre projet Supabase.

Créer des points d’accès au serveur d’authentification

Titre de la section Créer des points d’accès au serveur d’authentification

Pour ajouter l’authentification à votre projet, vous devrez créer quelques points de terminaison de serveur. Ces points seront utilisés pour enregistrer, connecter et déconnecter les utilisateurs.

  • POST /api/auth/register : pour enregistrer un nouvel utilisateur.
  • POST /api/auth/signin : pour enregistrer un utilisateur.
  • GET /api/auth/signout : pour déconnecter un utilisateur.

Créez ces points de terminaison dans le répertoire src/pages/api/auth de votre projet. Votre projet devrait maintenant inclure ces nouveaux fichiers :

  • Répertoiresrc/
    • Répertoirelib/
      • supabase.ts
    • Répertoirepages/
      • Répertoireapi/
        • Répertoireauth/
          • signin.ts
          • signout.ts
          • register.ts
    • env.d.ts
  • .env
  • astro.config.mjs
  • package.json

register.ts crée un nouvel utilisateur dans Supabase. Il accepte une requête POST avec l’email et le mot de passe. Il utilise ensuite le SDK de Supabase pour créer un nouvel utilisateur.

src/pages/api/auth/register.ts
import type { APIRoute } from "astro";
import { supabase } from "../../../lib/supabase";
export const POST: APIRoute = async ({ request, redirect }) => {
const formData = await request.formData();
const email = formData.get("email")?.toString();
const password = formData.get("password")?.toString();
if (!email || !password) {
return new Response("Email and password are required", { status: 400 });
}
const { error } = await supabase.auth.signUp({
email,
password,
});
if (error) {
return new Response(error.message, { status: 500 });
}
return redirect("/signin");
};

signin.ts crée un nouvel utilisateur dans Supabase. Il accepte une requête POST avec l’email et le mot de passe. Il utilise ensuite le SDK de Supabase pour créer un nouvel utilisateur

src/pages/api/auth/signin.ts
import type { APIRoute } from "astro";
import { supabase } from "../../../lib/supabase";
export const POST: APIRoute = async ({ request, cookies, redirect }) => {
const formData = await request.formData();
const email = formData.get("email")?.toString();
const password = formData.get("password")?.toString();
if (!email || !password) {
return new Response("Email and password are required", { status: 400 });
}
const { data, error } = await supabase.auth.signInWithPassword({
email,
password,
});
if (error) {
return new Response(error.message, { status: 500 });
}
const { access_token, refresh_token } = data.session;
cookies.set("sb-access-token", access_token, {
path: "/",
});
cookies.set("sb-refresh-token", refresh_token, {
path: "/",
});
return redirect("/dashboard");
};

signout.ts permet à un utilisateur de se déconnecter. Il accepte une requête GET et supprime les jetons d’accès et de rafraîchissement de l’utilisateur.

src/pages/api/auth/signout.ts
import type { APIRoute } from "astro";
export const GET: APIRoute = async ({ cookies, redirect }) => {
cookies.delete("sb-access-token", { path: "/" });
cookies.delete("sb-refresh-token", { path: "/" });
return redirect("/signin");
};

Création des pages d’authentification

Titre de la section Création des pages d’authentification

Maintenant que vous avez créé vos points d’accès au serveur, créez les pages qui les utiliseront.

  • src/pages/register : contient un formulaire pour enregistrer un nouvel utilisateur.
  • src/pages/signin : contient un formulaire pour enregistrer un utilisateur.
  • src/pages/dashboard : contient une page qui n’est accessible qu’aux utilisateurs authentifiés.

Créez ces pages dans le répertoire src/pages. Votre projet devrait maintenant inclure ces nouveaux fichiers :

  • Répertoiresrc/
    • Répertoirelib/
      • supabase.ts
    • Répertoirepages/
      • Répertoireapi/
        • Répertoireauth/
          • signin.ts
          • signout.ts
          • register.ts
      • register.astro
      • signin.astro
      • dashboard.astro
    • env.d.ts
  • .env
  • astro.config.mjs
  • package.json

register.astro contient un formulaire pour enregistrer un nouvel utilisateur. Il accepte un email et un mot de passe et envoie une requête POST à /api/auth/register.

src/pages/register.astro
---
import Layout from "../layouts/Layout.astro";
---
<Layout title="S'enregistrer">
<h1>S'enregistrer</h1>
<p>Vous avez déjà un compte ? <a href="/signin">Connexion</a></p>
<form action="/api/auth/register" method="post">
<label for="email">Email</label>
<input type="email" name="email" id="email" />
<label for="password">Mot de passe</label>
<input type="password" name="password" id="password" />
<button type="submit">S'enregistrer</button>
</form>
</Layout>

signin.astro contient un formulaire permettant d’identifier un utilisateur. Il accepte un email et un mot de passe et envoie une requête POST à /api/auth/signin. Il vérifie également la présence des jetons d’accès et de rafraîchissement. S’ils sont présents, il redirige vers le tableau de bord.

src/pages/signin.astro
---
import Layout from "../layouts/Layout.astro";
const { cookies, redirect } = Astro;
const accessToken = cookies.get("sb-access-token");
const refreshToken = cookies.get("sb-refresh-token");
if (accessToken && refreshToken) {
return redirect("/dashboard");
}
---
<Layout title="Connexion">
<h1>Connexion</h1>
<p>Nouveau par ici ? <a href="/register">Se créer un compte</a></p>
<form action="/api/auth/signin" method="post">
<label for="email">Email</label>
<input type="email" name="email" id="email" />
<label for="password">Mot de passe</label>
<input type="password" name="password" id="password" />
<button type="submit">Se connecter</button>
</form>
</Layout>

dashboard.astro contient une page qui n’est accessible qu’aux utilisateurs authentifiés. Elle vérifie la présence des jetons d’accès et de rafraîchissement. S’ils ne sont pas présents, elle redirige vers la page de connexion.

src/pages/dashboard.astro
---
import Layout from "../layouts/Layout.astro";
import { supabase } from "../lib/supabase";
const { cookies, redirect } = Astro;
const accessToken = cookies.get("sb-access-token");
const refreshToken = cookies.get("sb-refresh-token");
if (!accessToken || !refreshToken) {
return redirect("/signin");
}
const { data, error } = await supabase.auth.setSession({
refresh_token: refreshToken.value,
access_token: accessToken.value,
});
if (error) {
cookies.delete("sb-access-token", {
path: "/",
});
cookies.delete("sb-refresh-token", {
path: "/",
});
return redirect("/signin");
}
const email = data.user?.email;
---
<Layout title="dashboard">
<h1>Bienvenue {email}</h1>
<p>Nous sommes heureux de vous voir ici.</p>
<form action="/api/auth/signout">
<button type="submit">Se déconnecter</button>
</form>
</Layout>

Pour ajouter l’authentification OAuth à votre projet, vous devez éditer votre client Supabase pour activer le flux d’authentification avec "pkce". Vous pouvez en savoir plus sur les flux d’authentification dans la documentation Supabase.

src/lib/supabase.ts
import { createClient } from "@supabase/supabase-js";
export const supabase = createClient(
import.meta.env.SUPABASE_URL,
import.meta.env.SUPABASE_ANON_KEY,
{
auth: {
flowType: "pkce",
},
},
);

Ensuite, dans le tableau de bord de Supabase, activez le fournisseur OAuth que vous souhaitez utiliser. Vous pouvez trouver la liste des fournisseurs supportés dans l’onglet Authentication > Providers de votre projet Supabase.

L’exemple suivant utilise GitHub comme fournisseur OAuth. Pour connecter votre projet à GitHub, suivez les étapes de la documentation Supabase.

Ensuite, créez un nouveau point de terminaison serveur pour gérer le rappel OAuth dans src/pages/api/auth/callback.ts. Ce point de terminaison sera utilisé pour échanger le code OAuth contre un jeton d’accès et de rafraîchissement.

src/pages/api/auth/callback.ts
import type { APIRoute } from "astro";
import { supabase } from "../../../lib/supabase";
export const GET: APIRoute = async ({ url, cookies, redirect }) => {
const authCode = url.searchParams.get("code");
if (!authCode) {
return new Response("No code provided", { status: 400 });
}
const { data, error } = await supabase.auth.exchangeCodeForSession(authCode);
if (error) {
return new Response(error.message, { status: 500 });
}
const { access_token, refresh_token } = data.session;
cookies.set("sb-access-token", access_token, {
path: "/",
});
cookies.set("sb-refresh-token", refresh_token, {
path: "/",
});
return redirect("/dashboard");
};

Ensuite, modifiez la page de connexion pour inclure un nouveau bouton permettant de se connecter avec le fournisseur OAuth. Ce bouton doit envoyer une requête POST à /api/auth/signin avec le provider fixé au nom du fournisseur OAuth.

src/pages/signin.astro
---
import Layout from "../layouts/Layout.astro";
const { cookies, redirect } = Astro;
const accessToken = cookies.get("sb-access-token");
const refreshToken = cookies.get("sb-refresh-token");
if (accessToken && refreshToken) {
return redirect("/dashboard");
}
---
<Layout title="Connexion">
<h1>Connexion</h1>
<p>Nouveau par ici ? <a href="/register">Créer un compte</a></p>
<form action="/api/auth/signin" method="post">
<label for="email">Email</label>
<input type="email" name="email" id="email" />
<label for="password">Mot de passe</label>
<input type="password" name="password" id="password" />
<button type="submit">Login</button>
<button value="github" name="provider" type="submit">Se connecter avec GitHub</button>
</form>
</Layout>

Enfin, modifiez le point de terminaison du serveur de connexion pour gérer le fournisseur OAuth. Si le provider est présent, il redirigera vers le fournisseur OAuth. Sinon, il connectera l’utilisateur avec son email et son mot de passe.

src/pages/api/auth/signin.ts
import type { APIRoute } from "astro";
import { supabase } from "../../../lib/supabase";
import type { Provider } from "@supabase/supabase-js";
export const POST: APIRoute = async ({ request, cookies, redirect }) => {
const formData = await request.formData();
const email = formData.get("email")?.toString();
const password = formData.get("password")?.toString();
const provider = formData.get("provider")?.toString();
const validProviders = ["google", "github", "discord"];
if (provider && validProviders.includes(provider)) {
const { data, error } = await supabase.auth.signInWithOAuth({
provider: provider as Provider,
options: {
redirectTo: "http://localhost:4321/api/auth/callback"
},
});
if (error) {
return new Response(error.message, { status: 500 });
}
return redirect(data.url);
}
if (!email || !password) {
return new Response("L'adresse e-mail et le mot de passe sont nécessaires", { status: 400 });
}
const { data, error } = await supabase.auth.signInWithPassword({
email,
password,
});
if (error) {
return new Response(error.message, { status: 500 });
}
const { access_token, refresh_token } = data.session;
cookies.set("sb-access-token", access_token, {
path: "/",
});
cookies.set("sb-refresh-token", refresh_token, {
path: "/",
});
return redirect("/dashboard");
};

Après avoir créé le point d’accès OAuth et modifié la page de connexion et le point d’accès au serveur, votre projet devrait avoir la structure de fichier suivante :

  • Répertoiresrc/
    • Répertoirelib/
      • supabase.ts
    • Répertoirepages/
      • Répertoireapi/
        • Répertoireauth/
          • signin.ts
          • signout.ts
          • register.ts
          • callback.ts
      • register.astro
      • signin.astro
      • dashboard.astro
    • env.d.ts
  • .env
  • astro.config.mjs
  • package.json

Plus de guides sur les services backend