Olá, me chamo Lucas Frazão. Trabalho como desenvolvedor de software (SWE) há 5 anos.
Nesse post nós iremos construir um fluxo simples de autenticação utilizando ReactJS (v.18.3) e Supabase. Durante a construção de aplicações pessoais, é comum precisarmos adicionar uma autenticação. Então, eu gostaria de te mostrar como você pode fazer isso utilizando supabase auth.
O que é supabase?
O supabase é uma alternativa open source ao Firebase que utiliza PostgreSQL. Isso significa que ele pode ser usado para diversos fins além de autenticação, como armazenar e organizar imagens e dados, construir aplicativos de chat em tempo real, gerenciar autenticação de usuário e muito mais. Você pode encontrar mais informações na documentação oficial: https://supabase.com/docs
Vamos comecar
Para manter as coisas simples eu escolhi o vitejs como ferramenta para montar o ambiente, npm como gerenciador de pacotes node e o typescript por gostar bastante da stack.
Disclaimer: Esse tutorial pode ser seguido utilizando tanto TypeScript quanto JavaScript.
Primeiro passo é construir nossa aplicação para conectar com o supabase, vamos lá.
Execute o comando:
npm create vite@latest
Vou utilizar "auth-supabase" como nome do meu projeto mas voce pode escolher livremente outro nome.
npm create vite@latest
? Project name: › auth-supabase
Selecione React como framework:
✔ Project name: … auth-supabase
? Select a framework: › - Use arrow-keys. Return to submit.
Vanilla
Vue
❯ React
Preact
Lit
Svelte
Solid
Qwik
Others
Selecione TypeScript (ou JavaScript) como variante:
✔ Project name: … auth-supabase
✔ Select a framework: › React
? Select a variant: › - Use arrow-keys. Return to submit.
❯ TypeScript
TypeScript + SWC
JavaScript
JavaScript + SWC
Remix ↗
Agora vamos navegar até a pasta do nosso projeto e limpar algumas coisas que o vite deixa pronto.
Execute o comando:
cd auth-supabase && code .
Agora, para simplificar a estrutura do projeto, vamos seguir algumas etapas. Começando com:
-> Delete a pasta src/assets
.
-> Substitua todo o conteúdo do arquivo src/index.css
pelo código abaixo:
*,
:after,
:before {
box-sizing: border-box;
}
body {
margin: 0;
min-height: 100vh;
scroll-behavior: smooth;
text-rendering: optimizeSpeed;
font-synthesis: none;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
a, button {
color: inherit;
cursor: pointer;
}
-> Substitua todo o conteúdo do arquivo src/App.tsx
pelo código abaixo:
import { FormEvent } from "react";
import "./App.css";
export default function App() {
function handleSubmit(event: FormEvent<HTMLFormElement>) {
event.preventDefault();
const data = new FormData(event.currentTarget);
const email = data.get("email")?.toString();
const password = data.get("password")?.toString();
console.log({ email, password });
}
return (
<main>
<h1>Sign in with supabase</h1>
<form onSubmit={handleSubmit}>
<label htmlFor="email">E-mail</label>
<input
type="text"
name="email"
placeholder="email@email.com"
required
/>
<label htmlFor="password">Password</label>
<input
type="password"
name="password"
placeholder="********"
required
/>
<button type="submit">Login</button>
</form>
</main>
);
}
Precisamos instalar as dependências, então execute:
npm install
Excelente! Se você não teve nenhum erro durante as etapas anteriories, nós podemos seguir com as configurações do supabase para nosso projeto.
Durante esse tutorial nosso foco será um fluxo tradicional de login, com username e senha mas, o supabase tem supor para login social. Se você se interessar por essa opção, pode conferir a documentação oficial que tem mais detalhes:
https://supabase.com/docs/guides/auth/social-login
Para instalar o supabase, execute o comando:
npm install @supabase/supabase-js
Podemos verificar se tudo deu certo através do package.json
Uma vez que completamos essa etapa, execute o comando abaixo para executar um servidor local da aplicação:
npm run dev
Então, você conseguir acessar a aplicação no browser através da urlÇ http://localhost:5173/ .
Você irá ver algo assim:
Vamos configurar nossa autenticação. Lembre se, é necessário criar uma conta no supabase para continuar com essas configurações.
-> Selecione "New organization"
-> Clique em "Create organization" e preencha todos os campos
-> Para criar um novo projeto, é necessário preencha todos os campos abaixo. Na parte de database password, você pode clicar em "Generate a password" e depois em "copy" para gerar uma senha automática, certifique se de manter essa senha guardada.
Você não precisar alterar nenhuma configuração no meun "security options", basta clicar em "Create new project" para continuar.
Agora o supabase está configurando nosso projeto.
-> No menu lateral, localize a opção "Authentication" e clique nela.
-> No meu de opções "Add user" selecione a opção "Create New User" para adicionar um novo usuário.
Observação: Durante esse tutorial vou demonstrar uma criação "direta" de um novo usuário, mas geralmente é recomendado priorizar a segurança em aplicações reais. Pensando nisso, caso deseja aplicar em uma aplicação pública, considere selecionar a opção "send invitation", que irá permitir o usuário confirmar seu cadastro, verificando a conta e trocando sua senha. Além disso, explore metódos diferentes de autenticação que o supabase oferece para encontrar aquele que se encaixa melhor com o seu cenário.
-> Preencha com email e senha. Então, selecione "Create user" e deixe marcado a opção "Auto Confirm User?"
Agora nós temos um usuário para testar a conexão entre o supabase e a nossa aplicação. Vamos navegar até a página home e selecionar a opção "Connect".
-> Clique em "Connect", no lado direito da página.
-> Copie todo o conteúdo da aba .env
-> Na nossa aplicação, crie um arquivo .env e adicione os valores copiados anteriormente:
No Vite.js, as variáveis de ambiente são prefixadas com
VITE_
por padrão. Você pode encontrar mais detalhes sobre as variáveis de ambiente na documentação oficial do Vite:
https://vitejs.dev/guide/env-and-mode
Agora, vamos criar uma função utilitária para o supabase. Vamos seguir os passos abaixo.
-
Criar uma nova pasta: Dentro do diretório
src
crie uma pasta com o nomeutils
. -
Crie um arquivo TypeScript: Dentro da basta
utils
adicione um arquivo chamadosupabase.ts
. -
Adicionando código: Cole o código abaixo dentro do seu arquivo
supabase.ts
.
import { createClient } from "@supabase/supabase-js";
const supabaseUrl = import.meta.env.VITE_SUPABASE_URL;
const supabaseKey = import.meta.env.VITE_SUPABASE_ANON_KEY;
export const supabase = createClient(supabaseUrl, supabaseKey);
Agora finalizamos toda a configuração do supabase, vamos para integração.
Etapa final
Nós já temos os valores do email e senha armazenados em variáveis na função handleSubmit()
, mas só utilizamos no console.log, então vamos fazer algumas alterações. Vamos refatorar essa função tornado ela assíncrona e adiciona um bloco try-catch.
async function handleSubmit(event: FormEvent<HTMLFormElement>) {
event.preventDefault();
const data = new FormData(event.currentTarget);
const email = data.get("email")?.toString();
const password = data.get("password")?.toString();
try {
console.log({ email, password });
} catch (error) {
console.error(error);
}
}
Alguns benefícios ao utilizar try-catch em funções de submit e chamadas para api:
- Prevenir fluxos inesperados: Capturando possíveis erros na submissão ou chamada da api, você pode manipular fluxos para melhorar a experiência do usuário.
- Customização de erros: O bloco try-catch permite você prover mensages de erro ou feedbacks ao usuários dependendo do erro durante a submissão ou chamada à api.
Excelentes melhorias! Construindo essa manipulação de erros, podemos adicionar mais uma validação báisca antes do try-catch para evitar que valores undefined sejam passadas para a chamada da api.
if (!email || !password) return;
Agora, vamos importar a função supabase
do nosso supabase.ts
para dentro do arquivo src/App.tsx
. Assim, nós podemos utiliza la dentro da função handleSubmit()
.
import { supabase } from "./utils/supabase";
/* code ... **/
async function handleSubmit(event: FormEvent<HTMLFormElement>) {
event.preventDefault();
const data = new FormData(event.currentTarget);
const email = data.get("email")?.toString();
const password = data.get("password")?.toString();
if (!email || !password) return;
try {
const {} = await supabase.auth.signInWithPassword({ email, password });
} catch (error) {
console.error(error);
}
}
É possível acessar duas propriedades através da função signInWithPassword()
, error e data, nós iremos utilizar data
para capturar o token na aplicação e error
para retornar um erro para o usuário. Observer, nós alteramos o nome da variável data
para response
, pois já utilizamos uma variável chamada data
dentro desse escopo.
const { error, data: response } = await supabase.auth.signInWithPassword({
email,
password,
});
Agora que já incorporamos um bloco try-catch e temos acesso ao objeto de erro, vamos adicionar uma validação condicional. Essa condicional irá determinar se iremos manipular o erro através de um throw new Error
ou armazenar o token em local storage.
async function handleSubmit(event: FormEvent<HTMLFormElement>) {
event.preventDefault();
const data = new FormData(event.currentTarget);
const email = data.get("email")?.toString();
const password = data.get("password")?.toString();
if (!email || !password) return;
try {
const { error, data: response } = await supabase.auth.signInWithPassword({
email,
password,
});
if (error) {
throw new Error(error.message);
} else {
const accessToken = response.session?.access_token;
localStorage.setItem("access_token", accessToken);
}
} catch (error) {
console.error("occured an error:", error);
}
}
Para verificar se tivemos sucesso no login, podemos verificar o local storage do navegador. Seguindo os após:
-
Abrir o developer tools:
-
Windows: Pressione
Ctrl + Shift + J
simultaneamente. -
macOS: Pressione
Command (⌘) + Option (⌥) + J
simultaneamente.
-
Windows: Pressione
- Navegue até a aba "Aplicação".
- No menu sidebar, à esquerda, selecione a seção "Local Storage".
- Veja se encontra uma key chamada "access_token". A presença dessa chave e seu valor indica que tivemos sucesso no login. Você deve ver algo assim:
Bônus
Agora que nós estabelecemos um fluxo de login, vamos explorar como implementar a funcionalidade de deslogar.
O processo de deslogar é bem semelhante ao utilizado na função handleSubmit()
. Basicamente, seguiremos o mesmo padrão e chamada. Observe o código de exemplo abaixo para mais detalhes da implementação.
async function handleSignOut() {
try {
const { error } = await supabase.auth.signOut();
if (error) {
throw new Error(error.message);
}
} catch (error) {
console.error(error);
}
}
É importante adicionar um botão que executa a função signOut()
.
<button type="button" onClick={handleSignOut}>
sign out
</button>
Após clicar no botão de signOut()
, você pode verificar que o fluxo de deslogar funcionou verificando novamente o local storage no seu navegador. O supabase utiliza local storage para armazenada objetos de autenticação, conforme o print, um fluxo de deslogar com sucesso irá deletar esse objeto criado pelo supabase.
Lembre se, a chava chamada access_token foi criada por nós anteriormente. Após deslogar, podemos remover essa chave para garantir que a sessão do usuário seja encerrada. Abaixo temos um exemplo de adicionar essa funcionalidade dentro do
handleSubmit()
.
// Add this if you want to clear all localStorage
if (error) {
throw new Error(error.message);
} else {
localStorage.clear()
}
// Add this if you want to delete an especific key
if (error) {
throw new Error(error.message);
} else {
localStorage.removeItem('access_token')
}
Conclusão
Nós construimmos um fluxo de autenticação do usuário utilizando supabase na nossa aplicação. Esse tutorial cobriu algumas etapas importantes como inicialização e configuração do supabase, sign in, sign out e gereciamento do local storage. Agora nós temos um conhecimento sólido sobre como funcionar uma autenticação com o supabase.
Sinta se livre para customizar esse fluxo e explorar mais funcionalidades do supabase, além de deixar seu comentário ou me enviar um feedback!
Top comments (0)