Procure o emoji 🛠️ se quiser passar pelo conteúdo enquanto se concentra nas etapas de implementação.
O foco deste tutorial é ajudar pessoas desenvolvedoras a aprender como proteger uma aplicação React implementando a autenticação de usuário. Você vai melhorar uma aplicação React inicial para praticar os seguintes conceitos de segurança:
- Adicionar login e logout de usuário.
- Recuperar informações de usuário.
- Proteger a rota da aplicação.
- Chamar endpoints protegidos de uma API.
Este guia usa o SDK da Auth0 para proteger as aplicações React, que fornece às pessoas desenvolvedoras de React uma maneira mais fácil de adicionar autenticação de usuário para aplicações React, usando uma abordagem centrada em hooks. O SDK da Auth0 para React fornece uma API de alto nível para lidar com muitos detalhes de implementação de autenticação. Agora você pode proteger suas aplicações React usando as melhores práticas de segurança enquanto escreve menos código.
⚠️ Este guia usa React Hooks e componentes de função para construir uma aplicação React segura. Se precisar implementar qualquer componente deste guia usando classes JavaScript, verifique o repositório
enquanto lê. Existe um arquivo baseado em auth0-react-sample-classes
class
equivalente para cada arquivo criado neste guia.Como funciona a Auth0?
Com a ajuda da Auth0, você não precisa ser um especialista em protocolos de identidade, como OAuth 2.0 ou OpenID Connect, para entender como proteger suas aplicações. Primeiro, você integra sua aplicação com a Auth0. Sua aplicação redirecionará os usuários para uma página de login personalizável da Auth0. Após seus usuários fazerem login com sucesso, Auth0 os redireciona de volta para a sua aplicação, retornando JSON Web Tokens (JWTs) com autenticação e informações de usuário.
⏰⚡️ Se você tiver pouco tempo, consulte o Guia de Início Rápido React da Auth0 para começar a usar a autenticação de usuário em React em apenas alguns minutos. Você também pode conferir a nossa playlist do YouTube “React e Auth0”.
Obtenha a Aplicação Inicial
Criamos um projeto inicial usando um
para aprender os conceitos de segurança do React através da prática. A aplicação inicial usa Bootstrap com um tema personalizado para cuidar do estilo e do layout das suas aplicações. Você pode se concentrar na construção de componentes React para proteger sua aplicação.create-react-app
🛠 Agora, clone o repositório
auth0-react-sample
em seu branch starter
para começar:git clone -b starter git@github.com:auth0-blog/auth0-react-sample.git
🛠 Depois de clonar o repositório, torne
auth0-react-sample
seu diretório atual:cd auth0-react-sample
🛠 Instale as dependências do projeto React:
npm install
Conecte O React Com a Auth0
A melhor parte da plataforma Auth0 é a simplicidade para começar seguindo estas etapas:
Inscreva-se e crie uma aplicação Auth0
Se ainda não o fez,
cadastre-se para obter uma conta Auth0 gratuita🛠 Se ainda não o fez, cadastre-se para obter uma conta Auth0 gratuita.
Uma conta gratuita oferece:
- 7.000 usuários ativos gratuitos e logins ilimitados.
- Login Universal Auth0 para Web, iOS e Android.
- Até 2 provedores de identidade social, como Google, GitHub e Twitter.
- Serverless ilimitados para personalizar e estender os recursos da Auth0.
Durante o cadastro, você cria um Auth0 Tenant, que representa o produto ou serviço ao qual você está adicionando autenticação.
🛠 Depois de se inscrever, Auth0 leva você para o Dashboard. No menu da barra lateral esquerda, clique em "Applications".
🛠 Em seguida, clique no botão "Create Application". Irá abrir um formulário para que você escreva o nome e o tipo da aplicação.
- Name (nome):
Auth0 React Sample
- Application type (Tipo da aplicação): Single Page Web Applications (Aplicações Web de Página Única)
🛠 Clique no botão "Create" para concluir o processo. A página da sua aplicação Auth0 é carregada.
Na próxima etapa, você aprenderá como fazer o React e a Auth0 se comunicarem.
Qual é a relação entre Auth0 Tenants e aplicações Auth0?
Digamos que você tenha uma aplicação React de compartilhamento de fotos chamado “Rectogram”. Você então criaria um Auth0 tenant chamado
reactogram
. Do ponto de vista do cliente, o Reactogram é o produto ou serviço desse cliente.Agora, digamos que o Reactogram esteja disponível em três plataformas: na web como uma aplicação de página única (Single Page Application ou SPA em inglês) e como um aplicativo móvel nativo para Android e iOS. Se cada plataforma precisar de autenticação, você precisará criar três aplicações Auth0 para fornecer ao produto tudo o que a pessoa precisa para autenticar os usuários por meio dessa plataforma.
Os usuários do Reactogram pertenceriam ao Auth0 tentant Reactogram, que os compartilha em suas aplicações Auth0. Se você lançasse outro produto chamado "Reactiktok" que precisa de autenticação, precisaria criar outro tenant,
reactiktok
, e criar aplicações Auth0 para dar suporte às plataformas em que ele é suportado.Crie uma ponte de comunicação entre React e Auth0
Ao usar a Auth0, você não precisa criar formulários de login. A Auth0 oferece uma página de login universal para reduzir a sobrecarga de adição e gerenciamento de autenticação.
Como funciona o Login Universal?
Sua aplicação React redirecionará os usuários para a Auth0 sempre que eles dispararem uma requisição de autenticação. A Auth0 irá apresentar uma página de login. Assim que eles fizerem login, a Auth0 os redirecionará de volta para a sua aplicação React. Para que o redirecionamento ocorra com segurança, você deve especificar nas suas configurações de aplicações Auth0 as URLs para os quais a Auth0 pode redirecionar usuários, uma vez que estejam autenticados.
🛠 Clique na guia "Settings" da página da aplicação Auth0 e preencha os seguintes valores:
🛠 URLs de callback permitidas (Allowed Callback URLs em inglês)
http://localhost:4040
O valor acima é a URL que a Auth0 pode usar para redirecionar seus usuários depois que eles fizerem login.
🛠 URLs de logout permitidas (Allowed Logout URLs em inglês)
http://localhost:4040
O valor acima é a URL que a Auth0 pode usar para redirecionar seus usuários após o logout.
🛠 Origens Web permitidas (Allowed Web Origins em inglês)
http://localhost:4040
Usando o SDK da Auth0 para React, sua aplicação React fará requisições internas a uma URL da Auth0 para lidar com as requisições de autenticação. Você precisa adicionar a URL de origem da aplicação React para evitar problemas de Compartilhamento de recursos de origem cruzada (Cross-Origin Resource Sharing - CORS).
🛠 Role para baixo e clique no botão "Save changes".
🛠 Não feche esta página ainda. Você precisará de algumas informações na próxima seção.
Adicione as variáveis de configuração da Auth0 ao React
Na aba "Settings" da página da aplicação Auth0, você precisa dos valores de Domínio Auth0 (Auth0 Domain em inglês) e ID do Cliente (Client ID em inglês) para permitir que sua aplicação React use a ponte de comunicação que você criou.
O que exatamente é um domínio Auth0 e um ID de cliente Auth0?
Domínio
Quando você criou uma nova conta Auth0, a Auth0 pediu para escolher um nome para seu tenant. Este nome, anexado com
auth0.com
, é o seu domínio Auth0 (Auth0 Domain em inglês). É a URL base que você usará para acessar as APIs Auth0 e a URL para onde você redirecionará os usuários para fazer login.Você também pode usar domínios personalizados para permitir que a Auth0 faça o trabalho pesado de autenticação para você sem comprometer sua experiência de branding.
ID de cliente
Cada aplicação recebe um ID de cliente (Client ID) ao ser criada, que é uma string alfanumérica, e é o identificador exclusivo da sua aplicação (como
q8fij2iug0CmgPLfTfG1tZGdTQyGaTUA
). Você não pode modificar o ID do cliente. Você usará o ID do cliente para identificar a aplicação Auth0 que o SDK da Auth0 para React precisa se conectar.Atenção: Outra informação crítica presente nas "Settings" é o Segredo do Cliente (Client Secret em inglês). Esse segredo protege seus recursos concedendo tokens apenas para solicitantes se estiverem autorizados. Pense nisso como a senha da sua aplicação, que deve ser mantida em sigilo o tempo todo. Se alguém obtiver acesso ao seu Client Secret, poderá se passar pela sua aplicação e acessar recursos protegidos.
🛠 Abra o projeto inicial do React,
auth0-react-sample
e crie um arquivo .env
o diretório do projeto:touch .env
🛠 Preencha o
.env
da seguinte forma:REACT_APP_AUTH0_DOMAIN= REACT_APP_AUTH0_CLIENT_ID=
🛠 Volte para a página da aplicação Auth0. Siga estas etapas para obter os valores
REACT_APP_AUTH0_DOMAIN
eREACT_APP_AUTH0_CLIENT_ID
:- 🛠 Clique na guia "Settings", se ainda não tiver feito isso.
- 🛠 Use o valor "Domain" em "Settings" como o valor de
noREACT_APP_AUTH0_DOMAIN
..env
- 🛠 Use o valor "Client ID" em "Settings" como o valor de
noREACT_APP_AUTH0_CLIENT_ID
..env
Essas variáveis permitem que sua aplicação React se identifique como uma parte autorizada para interagir com o servidor de autenticação Auth0.
Conexão Auth0 e React
Você concluiu a configuração de um serviço de autenticação que sua aplicação React pode consumir. Continue construindo o projeto inicial ao longo deste guia, implementando componentes para acionar e gerenciar o fluxo de autenticação.
Descubra mais na documentação da Auth0 para saber mais sobre como a Auth0 ajuda a economizar tempo na implementação e gerenciamento de identidade.
Configure O SDK Da Auth0 Para React
🛠 Você precisa seguir estas etapas para integrar o SDK da Auth0 com sua aplicação React.
Instale o SDK da Auth0 para React
🛠 Execute o seguinte comando:
npm install @auth0/auth0-react
Configure o componente Auth0Provider
Por baixo dos panos, o SDK da Auth0 para React usa o React Context. O SDK usa um componente
Auth0Context
para gerenciar o estado de autenticação de seus usuários. Por sua vez, o SDK expõe o componente Auth0Provider
, que fornece esse Auth0Context
para seus componentes filhos. Como tal, você pode envolver seu componente raiz, como o App
, com Auth0Provider
para integrar a Auth0 com sua aplicação React.<Auth0Provider> <App /> </Auth0Provider>
No entanto, a autenticação de usuário é um mecanismo para monitorar quem está acessando sua aplicação e controlar o que essas pessoas podem fazer. Por exemplo, você pode impedir que usuários que não tenham efetuado login acessem partes da sua aplicação. Nesse cenário, Auth0 pode atuar como bouncer da aplicação.
Um bouncer é uma pessoa empregada por uma boate ou estabelecimento similar para impedir que encrenqueiros entrem ou os expulsem do local. A segurança do React não é muito diferente da segurança de uma boate.
Se os usuários quiserem acessar uma rota protegida da sua aplicação, Auth0 irá interrompê-los e solicitar que apresentem suas credenciais. Se a Auth0 puder verificar quem são e se devem entrar lá, a Auth0 os deixará entrar. Caso contrário, a Auth0 os levará de volta para uma rota pública da aplicação.
Agora, é importante reiterar que o processo de autenticação não acontecerá na sua aplicação. Sua aplicação React redirecionará seus usuários para a página de Login Universal da Auth0, onde a Auth0 solicita as credenciais e redireciona o usuário de volta à sua aplicação com o resultado do processo de autenticação.
O
Auth0Provider
lembra para onde o usuário queria ir e, se a autenticação for bem-sucedida, leva o usuário para essa rota. Por isso, o Auth0Provider
precisa ter acesso ao histórico de sessão da aplicação. A aplicação inicial React usa React Router para gerenciar seu roteamento. O React Router expõe um React Hook que facilita o acesso ao histórico da sessão por meio de um objeto history
, useHistory()
.Consequentemente, você precisa envolver o
Auth0Provider
com BrowserRouter
do React Router, que usa um componente RouterContext.Provider
por baixo dos panos para manter o estado de roteamento:<BrowserRouter> <Auth0Provider> <App /> </Auth0Provider> </BrowserRouter>
Aqui, o que você vê em jogo é um pilar da arquitetura do React: você estende os componentes, não por herança, mas por composição.
Como você cria um
com acesso ao histórico de sessão da aplicação?Auth0Provider
🛠 Comece criando um diretório
auth
no diretório src
:mkdir src/auth
🛠 Crie um arquivo
auth0-provider-with-history.js
no diretório src/auth
para definir um componente Auth0ProviderWithHistory
que usa composição para disponibilizar React Router Hooks para Auth0Provider
:touch src/auth/auth0-provider-with-history.js
🛠 Preencha o
src/auth/auth0-provider-with-history.js
com o seguinte:// src/auth/auth0-provider-with-history.js import React from "react"; import { useHistory } from "react-router-dom"; import { Auth0Provider } from "@auth0/auth0-react"; const Auth0ProviderWithHistory = ({ children }) => { const domain = process.env.REACT_APP_AUTH0_DOMAIN; const clientId = process.env.REACT_APP_AUTH0_CLIENT_ID; const history = useHistory(); const onRedirectCallback = (appState) => { history.push(appState?.returnTo || window.location.pathname); }; return ( <Auth0Provider domain={domain} clientId={clientId} redirectUri={window.location.origin} onRedirectCallback={onRedirectCallback} > {children} </Auth0Provider> ); }; export default Auth0ProviderWithHistory;
O que está acontecendo no
Auth0ProviderWithHistory
?- Você precisa do SDK da Auth0 para React para se conectar à aplicação Auth0 correta para processar a autenticação. Assim, você precisa do Auth0 Domain e Client ID para configurar o
.Auth0Provider
- Use o método
para manipular o evento em que Auth0 redireciona seus usuários da página de login universal da Auth0 para a aplicação React. Use o hookonRedirectCallback()
para obter o objetouseHistory()
do React Router. Use o métodohistory
para levar os usuários de volta à rota que pretendiam acessar antes da autenticação.history.push()
É isso! Envolver qualquer árvore de componentes com
Auth0ProviderWithHistory
dará acesso ao Auth0Context
.Como você usa o Auth0ProviderWithHistory
O
Auth0ProviderWithHistory
requer que o componente BrowserRouter
do React Router seja seu pai, avô ou tataravô.O
Context
do React Router deve estar presente na árvore de componentes em um nível superior para que Auth0ProviderWithHistory
acesse o hook useHistory()
do React Router.🛠 Abra o arquivo
src/index.js
e atualize-o da seguinte forma para construir a árvore de componentes adequada para alimentar os recursos de roteamento e autenticação de usuário da sua aplicação React:// src/index.js import React from "react"; import ReactDOM from "react-dom"; import App from "./app"; import { BrowserRouter as Router } from "react-router-dom"; import Auth0ProviderWithHistory from "./auth/auth0-provider-with-history"; import "./index.css"; ReactDOM.render( <Router> <Auth0ProviderWithHistory> <App /> </Auth0ProviderWithHistory> </Router>, document.getElementById("root") );
🛠 Execute o seguinte comando para executar sua aplicação React:
npm start
O SDK da Auth0 para React está configurado. Agora você tem tudo que você precisa para implementar a autenticação do usuário na próxima seção.
Adicione Autenticação De Usuários
Você precisa fornecer elementos de interface de usuário (IU) para que seus usuários acionem eventos de autenticação: login, logout e inscrição.
Crie um botão de login
🛠 Crie um arquivo
login-button.js
no diretório src/components/
:touch src/components/login-button.js
🛠 Preencha
src/components/login-button.js
assim:// src/components/login-button.js import React from "react"; import { useAuth0 } from "@auth0/auth0-react"; const LoginButton = () => { const { loginWithRedirect } = useAuth0(); return ( <button className="btn btn-primary btn-block" onClick={() => loginWithRedirect()} > Log In </button> ); }; export default LoginButton;
é um método exposto pelo loginWithRedirect()
Auth0Context
. Chamar esse método solicita que um usuário autentique e dê consentimento para que sua aplicação React acesse determinados dados em nome deste usuário. Em sua arquitetura atual, isso significa que sua aplicação React redireciona o usuário para a página de login universal da Auth0 para realizar o processo de autenticação. Você verá isso em ação nas próximas seções.Você pode passar um objeto de configuração para
loginWithRedirect()
para personalizar a experiência de login. Por exemplo, você pode passar opções para redirecionar usuários a uma página de login universal Auth0 otimizada para se inscrever na sua aplicação React. Consulte RedirectLoginOptions
(em inglês) para obter mais detalhes sobre essas opções.Crie um botão de inscrição
Você pode fazer com que os usuários acessem diretamente uma página de inscrição em vez de uma página de login, especificando a propriedade
screen_hint=signup
no objeto de configuração loginWithRedirect()
:{ screen_hint: "signup", }
🛠 Crie um arquivo
signup-button.js
no diretório src/components/
:touch src/components/signup-button.js
🛠 Preencha
src/components/signup-button.js
da mesma forma para definir um componente SignupButton
:// src/components/signup-button.js import React from "react"; import { useAuth0 } from "@auth0/auth0-react"; const SignupButton = () => { const { loginWithRedirect } = useAuth0(); return ( <button className="btn btn-primary btn-block" onClick={() => loginWithRedirect({ screen_hint: "signup", }) } > Sign Up </button> ); }; export default SignupButton;
O uso do recurso de inscrição exige que você ative o Auth0 New Universal Login Experience em seu tenant.
🛠 Abra a seção Login Universal do dashboard Auth0 e escolha a opção "New" na subseção "Experience".
🛠 Role para baixo e clique no botão "Save changes".
A diferença entre a experiência de usuário em
LoginButton
e SignupButton
ficará mais evidente quando você integrar esses componentes à aplicação React e vê-los em ação. Você fará isso nas próximas seções.Crie um botão de logout
🛠 Crie um arquivo
logout-button.js
no diretório src/components/
:touch src/components/logout-button.js
Preencha
src/components/logout-button.js
assim:// src/components/logout-button.js import React from "react"; import { useAuth0 } from "@auth0/auth0-react"; const LogoutButton = () => { const { logout } = useAuth0(); return ( <button className="btn btn-danger btn-block" onClick={() => logout({ returnTo: window.location.origin, }) } > Log Out </button> ); }; export default LogoutButton;
O método
logout()
exposto por Auth0Context
limpa a sessão da aplicação e redireciona para o endpoint Auth0 /v2/logout
para limpar a sessão Auth0. Com os métodos de login, você pode passar um argumento de objeto para logout()
para definir parâmetros para a chamada /v2/logout
. Este processo é praticamente invisível para o usuário. Consulte LogoutOptions
para obter mais detalhes.Aqui, você passa a opção
returnTo
para especificar a URL onde Auth0 deve redirecionar seus usuários após o logout. No momento, você está trabalhando localmente e as "Allowed Logout URLs" da sua aplicação Auth0 apontam para http://localhost:4040
.No entanto, se você for fazer o deploy da sua aplicação React para produção, será necessário adicionar a URL de logout de produção à lista "Allowed Logout URLs" e garantir que a Auth0 redirecione seus usuários para essa URL de produção e não para o
localhost
. Definir returnTo
como window.location.origin
fará exatamente isso.Leia mais sobre como funciona o Logout na Auth0 (em inglês).
Integre os botões de login e logout
Vamos envolver o
LoginButton
e o LogoutButton
em um componente chamado AuthenticationButton
.🛠 Crie um arquivo
authentication-button.js
no diretório src/components/
:touch src/components/authentication-button.js
🛠 Preencha
src/components/authentication-button.js
com o seguinte código:// src/components/authentication-button.js import React from "react"; import LoginButton from "./login-button"; import LogoutButton from "./logout-button"; import { useAuth0 } from "@auth0/auth0-react"; const AuthenticationButton = () => { const { isAuthenticated } = useAuth0(); return isAuthenticated ? <LogoutButton /> : <LoginButton />; }; export default AuthenticationButton;
isAuthenticated
é um valor booleano exposto pelo Auth0Context
. Seu valor é true
quando Auth0 autenticou o usuário e false
quando não o fez.Existem algumas vantagens em usar este wrapper de componente
AuthenticationButton
:Você pode construir interfaces flexíveis.
AuthenticationButton
serve como uma opção de "login/logout" que você pode colocar em qualquer lugar que precisar dessa funcionalidade de troca. No entanto, você ainda tem componentes LoginButton
e LogoutButton
separados para os casos em que você precise de sua funcionalidade de forma isolada. Por exemplo, você pode ter um LogoutButton
em uma página que somente usuários autenticados podem ver.Você pode construir interfaces extensíveis. Você pode facilmente trocar o componente
LoginButton
pelo componente SignupButton
em AuthenticationButton
para criar uma opção de "sign up/log out". Você também pode envolver a opção "sign up/log out" em um componente NewAuthenticationButton
.Você pode construir interfaces declarativas. Usando
AuthenticationButton
, você pode adicionar a funcionalidade de login e logout ao seu componente NavBar
, por exemplo, sem pensar nos detalhes de implementação de como a troca de autenticação funciona.🛠 Com isso em mente, crie um arquivo
auth-nav.js
no diretóriosrc/components/
:touch src/components/auth-nav.js
🛠 Preencha
src/components/auth-nav.js
assim:// src/components/auth-nav.js import React from "react"; import AuthenticationButton from "./authentication-button"; const AuthNav = () => ( <div className="navbar-nav ml-auto"> <AuthenticationButton /> </div> ); export default AuthNav;
🛠 Finalmente, abra o
nav-bar.js
no diretório src/components/
e atualize-o assim:// src/components/nav-bar.js import React from "react"; import MainNav from "./main-nav"; import AuthNav from "./auth-nav"; const NavBar = () => { return ( <div className="nav-container mb-3"> <nav className="navbar navbar-expand-md navbar-light bg-light"> <div className="container"> <div className="navbar-brand logo" /> <MainNav /> <AuthNav /> </div> </nav> </div> ); }; export default NavBar;
Por ter diferentes tipos de subcomponentes da barra de navegação, você pode estender cada um conforme necessário, sem reabrir e modificar o componente principal
NavBar
.🛠 Vá em frente e tente fazer o login. Sua aplicação React redireciona você para a página de login universal da Auth0. Você pode usar um formulário para fazer login com um nome de usuário e senha ou um provedor de identidade social como o Google. Observe que esta página de login também oferece a opção de se inscrever.
Faça um teste: use o componente SignupButton
SignupButton
Troque o componente
LoginButton
pelo componente SignupButton
na operação ternária definida no corpo do componente AuthenticationButton
.Ao clicar no botão "Sign Up" (Inscreva-se), você será direcionado para uma página com linguagem otimizada para incentivar a se inscrever em sua aplicação React.
Experimente isso!
Depois de concluir esse teste, troque
SignupButton
por LoginButton
para continuar com o restante deste guia.Você pode personalizar a aparência das novas páginas de Login Universal. Você também pode substituir qualquer texto na "New Experience" usando a API de Personalização de Texto.
Observe que, quando você termina de fazer login e a Auth0 redireciona você para sua aplicação React, o botão de login aparece rapidamente (cor azul) e, em seguida, o botão de logout é renderizado (cor vermelha).
A interface do usuário "pisca" porque sua aplicação React não sabe se a Auth0 já autenticou o usuário. Sua aplicação saberá o status de autenticação do usuário depois que o SDK da Auth0 para React for carregado.
🛠 Para corrigir a intermitência da IU, use o valor booleano
isLoading
exposto pelo Auth0Context
para renderizar o componente do App
assim que o SDK da Auth0 para React terminar de carregar.🛠 Abra o arquivo
src/app.js
e atualize-o da seguinte forma:// src/app.js import React from "react"; import { Route, Switch } from "react-router-dom"; import { useAuth0 } from "@auth0/auth0-react"; import { NavBar, Footer, Loading } from "./components"; import { Home, Profile, ExternalApi } from "./views"; import "./app.css"; const App = () => { const { isLoading } = useAuth0(); if (isLoading) { return <Loading />; } return ( <div id="app" className="d-flex flex-column h-100"> <NavBar /> <div className="container flex-grow-1"> <Switch> <Route path="/" exact component={Home} /> <Route path="/profile" component={Profile} /> <Route path="/external-api" component={ExternalApi} /> </Switch> </div> <Footer /> </div> ); }; export default App;
Enquanto o SDK está carregando, o componente de carregamento
Loading
, que é animado, é renderizado.Recupere Informações De Usuário
Depois que um usuário efetua login com sucesso, Auth0 envia um ID token para sua aplicação React. Os sistemas de autenticação, como Auth0, usam ID tokens na autenticação baseada em token para armazenar em cache as informações do perfil do usuário e fornecê-las a uma aplicação cliente. O armazenamento em cache de ID tokens pode contribuir para melhorias no desempenho e capacidade de resposta da sua aplicação React.
Você pode usar os dados do ID token para personalizar a interface do usuário da sua aplicação React. O SDK da Auth0 para React decodifica o ID token e armazena seus dados no objeto do
user
exposto pelo Auth0Context
. Algumas das informações do ID token incluem o nome, apelido, imagem e e-mail do usuário conectado.Como você pode usar o ID token para criar uma página de perfil para seus usuários?
🛠 Atualize o componente
Profile
em src/views/profile.js
da seguinte forma:// src/views/profile.js import React from 'react'; import { useAuth0 } from '@auth0/auth0-react'; const Profile = () => { const { user } = useAuth0(); const { name, picture, email } = user; return ( <div> <div className="row align-items-center profile-header"> <div className="col-md-2 mb-3"> <img src={picture} alt="Profile" className="rounded-circle img-fluid profile-picture mb-3 mb-md-0" /> </div> <div className="col-md text-center text-md-left"> <h2>{name}</h2> <p className="lead text-muted">{email}</p> </div> </div> <div className="row"> <pre className="col-12 text-light bg-dark p-4"> {JSON.stringify(user, null, 2)} </pre> </div> </div> ); }; export default Profile;
O que está acontecendo no componente
Profile
?- Você desestrutura o objeto
para obter ouser
,name
e opicture
.email
- Em seguida, você exibe essas três propriedades na interface do usuário. Como os dados vêm de um objeto simples, você não precisa buscá-los usando uma chamada assíncrona.
- Por fim, você exibe o conteúdo completo do ID token decodificado em uma caixa de código. Agora você pode ver todas as outras propriedades disponíveis para uso.
O componente
Profile
renderiza informações do usuário que você pode considerar protegidas. Além disso, a propriedade do user
é null
se não houver um usuário conectado. Portanto, de qualquer forma, este componente só deve renderizar se a Auth0 tiver autenticado o usuário.Como tal, você deve proteger a rota que renderiza este componente,
. Você aprenderá a fazer exatamente isso na próxima seção.http://localhost:4040/profile
Proteja Rotas
O SDK da Auth0 para React expõe um componente de ordem superior (High-Order Component - HOC),
withAuthenticationRequired
, que você pode usar para proteger as rotas.Você também pode usar withAuthenticationRequired
para criar um componente ProtectedRoute
para proteger as rotas de uma forma mais declarativa usando o React Router.Use um Higher-Order Component para proteger uma rota
🛠 Abra
src/views/profile.js
e atualize-o da seguinte maneira:// src/views/profile.js import React from 'react'; import { useAuth0, withAuthenticationRequired } from '@auth0/auth0-react'; import { Loading } from '../components'; const Profile = () => { const { user } = useAuth0(); const { name, picture, email } = user; return ( <div> <div className="row align-items-center profile-header"> <div className="col-md-2 mb-3"> <img src={picture} alt="Profile" className="rounded-circle img-fluid profile-picture mb-3 mb-md-0" /> </div> <div className="col-md text-center text-md-left"> <h2>{name}</h2> <p className="lead text-muted">{email}</p> </div> </div> <div className="row"> <pre className="col-12 text-light bg-dark p-4"> {JSON.stringify(user, null, 2)} </pre> </div> </div> ); }; export default withAuthenticationRequired(Profile, { onRedirecting: () => <Loading />, });
Quando você envolve seus componentes no componente de ordem superior
withAuthenticationRequired
e os usuários que não efetuaram login visitam uma página que renderiza esse componente, sua aplicação React redireciona esse usuário para a página de login. Depois que o usuário faz login, a Auth0 redireciona o usuário para a aplicação React e o Auth0Provider
leva os usuários para a página que pretendiam acessar antes do login.withAuthenticationRequired
leva os seguintes argumentos:- O componente que você deseja proteger.
- Um objeto de configuração para customizar o fluxo de autenticação,
. Este objeto assume as seguintes propriedades opcionais:WithAuthenticationRequiredOptions
: ele se comporta exatamente como as opções de configuração que você pode passar paraloginOptions
para personalizar a experiência de login.loginWithRedirect()
: permite especificar um caminho para o React redirecionar um usuário após a transação de login que o usuário acionou neste componente.returnTo
: renderiza um componente enquanto a aplicação React redireciona o usuário para a página de login.onRedirecting
No exemplo acima, os usuários que não efetuaram login veem o componente de carregamento
Loading
assim que acessam a rota /profile
:export default withAuthenticationRequired(Profile, { onRedirecting: () => <Loading />, });
O componente
onRedirecting
melhora a experiência do usuário, evitando o aparecimento de componentes de IU mistos (componentes protegidos e públicos).🛠 Experimente. Faça o log out e visite
. Sua aplicação React deve redirecionar você para a página de login universal da Auth0.http://localhost:4040/profile
E se você estiver usando o React Router?
Usar
withAuthenticationRequired
para envolver o componente diretamente não é a maneira mais declarativa de construir uma aplicação React. Se você olhasse as rotas definidas no componente App
, não seria capaz de dizer quais rotas estão protegidas e quais são públicas.const App = () => { const { isLoading } = useAuth0(); if (isLoading) { return <Loading />; } return ( <div id="app" className="d-flex flex-column h-100"> <NavBar /> <div className="container flex-grow-1"> <Switch> <Route path="/" exact component={Home} /> <Route path="/profile" component={Profile} /> <Route path="/external-api" component={ExternalApi} /> </Switch> </div> <Footer /> </div> ); };
🛠 Em vez de usar
withAuthenticationRequired
diretamente, você pode envolvê-lo em um componente ProtectedRoute
que aproveita os recursos do React Router.Crie um componente para proteger os caminhos do React Router
A aplicação inicial usa React Router como sua biblioteca de roteamento. Este exemplo se aplica apenas a essa biblioteca.
Nesta seção, você criará um componente
ProtectedRoute
que usa o componente Route
do React Router para renderizar o componente de ordem superior withAuthenticationRequired
. A vantagem dessa abordagem é que seu ProtectedRoute
terá a mesma API de um componente Route
pronto para uso. Dessa forma, você pode compor o ProtectedRoute
com outros componentes do React Router organicamente.🛠 Para começar, crie um arquivo
protected-route.js
no diretório src/auth
:touch src/auth/protected-route.js
🛠 Preencha
src/auth/protected-route.js
da seguinte forma:// src/auth/protected-route.js import React from 'react'; import { Route } from 'react-router-dom'; import { withAuthenticationRequired } from '@auth0/auth0-react'; import { Loading } from '../components/index'; const ProtectedRoute = ({ component, ...args }) => ( <Route component={withAuthenticationRequired(component, { onRedirecting: () => <Loading />, })} {...args} /> ); export default ProtectedRoute;
🛠 Por último, abra o arquivo
src/app.js
. Localize o componente Switch
e altere os componentes Route
para os caminhos /profile
e /external-api
para um componente ProtectedRoute
:// src/app.js import React from 'react'; import { Route, Switch } from 'react-router-dom'; import { useAuth0 } from '@auth0/auth0-react'; import { NavBar, Footer, Loading } from './components'; import { Home, Profile, ExternalApi } from './views'; import ProtectedRoute from './auth/protected-route'; import './app.css'; const App = () => { const { isLoading } = useAuth0(); if (isLoading) { return <Loading />; } return ( <div id="app" className="d-flex flex-column h-100"> <NavBar /> <div className="container flex-grow-1"> <Switch> <Route path="/" exact component={Home} /> <ProtectedRoute path="/profile" component={Profile} /> <ProtectedRoute path="/external-api" component={ExternalApi} /> </Switch> </div> <Footer /> </div> ); }; export default App;
Você não precisa mais usar componente de ordem superior
withAuthenticationRequired
diretamente no componente Profile
.🛠 Abra
src/views/profile.js
e reverta o arquivo ao seu conteúdo anterior:// src/views/profile.js import React from 'react'; import { useAuth0 } from '@auth0/auth0-react'; const Profile = () => { const { user } = useAuth0(); const { name, picture, email } = user; return ( <div> <div className="row align-items-center profile-header"> <div className="col-md-2 mb-3"> <img src={picture} alt="Profile" className="rounded-circle img-fluid profile-picture mb-3 mb-md-0" /> </div> <div className="col-md text-center text-md-left"> <h2>{name}</h2> <p className="lead text-muted">{email}</p> </div> </div> <div className="row"> <pre className="col-12 text-light bg-dark p-4"> {JSON.stringify(user, null, 2)} </pre> </div> </div> ); }; export default Profile;
🛠 Agora você pode testar se esses dois caminhos exigem que os usuários façam login antes de acessá-los. Faça o log out e tente acessar a página Profile ou External API. Se funcionar, o React redireciona você para fazer o login com Auth0.
Os protetores do lado do cliente melhoram a experiência do usuário em sua aplicação React, não sua segurança.
No Security StackExchange, Conor Mancone explica que as proteções do lado do servidor visam proteger os dados, enquanto as proteções do lado do cliente visam melhorar a experiência do usuário.
As principais conclusões de sua resposta são:
- Você não pode confiar em restrições do lado do cliente, como protetores de navegação e rotas protegidas, para proteger informações confidenciais.
- Os invasores podem eventualmente contornar as restrições do lado do cliente.
- Seu servidor não deve retornar nenhum dado que um usuário não deva acessar.
- Retornar todos os dados do usuário do servidor e permitir que o framework de front-end decida o que exibir e o que ocultar com base no status de autenticação do usuário é uma abordagem errada.
- Qualquer pessoa pode abrir as ferramentas para pessoa desenvolvedoras do navegador e inspecionar as solicitações de rede para visualizar todos os dados.
- O uso de protetores de navegação ajuda a melhorar a experiência do usuário, não a segurança do usuário.
- Sem protetores, um usuário que não fez login pode entrar em uma página com informações restritas e ver um erro, como "Acesso negado".
- Com protetores que correspondem às permissões do servidor, você pode impedir que os usuários vejam erros, impedindo-os de visitar a página restrita.
Qual estratégia de proteção de rota você prefere usar nas suas aplicações React? O componente de ordem superior
ou o componentewithAuthenticationRequired
? Por favor, conte nos comentários.ProtectedRoute
Chame Uma API
Esta seção se concentra em mostrar como obter um token de acesso (access token, em inglês) na sua aplicação React e como usá-lo para fazer chamadas de API para endpoints protegidos.
Ao usar a Auth0, você delega o processo de autenticação a um serviço centralizado. A Auth0 oferece a funcionalidade de fazer login e logout de usuários da aplicação React. No entanto, sua aplicação pode precisar acessar recursos protegidos de uma API.
Você também pode proteger uma API com Auth0. Existem vários guias de início rápido de API para te ajudar a integrar a Auth0 com sua plataforma de back-end.
Ao usar a Auth0 para proteger sua API, você também delega o processo de autorização a um serviço centralizado que garante que apenas aplicações de cliente aprovadas possam acessar recursos protegidos em nome de um usuário.
Como você pode fazer chamadas de API seguras a partir do React?
Sua aplicação React autentica o usuário e recebe um token de acesso da Auth0. A aplicação pode então passar esse token de acesso para sua API como uma credencial. Por sua vez, sua API pode usar bibliotecas Auth0 para verificar o token de acesso que recebe da aplicação e emitir uma resposta com os dados desejados.
Em vez de criar uma API do zero para testar os fluxos de autenticação e autorização entre o cliente e o servidor, você usará uma API de demonstração Express API que preparei para você.
Obtenha a API de demonstração Express API
🛠 Abra o terminal em uma nova janela e clone o repositório
auth0-express-js-sample
em algum lugar do sistema. Certifique-se de fazer o clone fora do diretório do projeto React.git clone git@github.com:auth0-blog/auth0-express-js-sample.git
🛠 Depois de clonar este repositório, torne o diretório
seu diretório atual:auth0-express-js-sample
cd auth0-express-js-sample
🛠 Instale as dependências do projeto Node.js:
npm install
Conecte a Express API com Auth0
Crie uma ponte de comunicação entre React e Auth0
Este processo é semelhante a como você conectou o React à Auth0.
🛠 Vá para a seção APIs no Dashboard da Auth0 e clique no botão "Create API".
🛠 Então, a Auth0 mostra:
- Adicione um nome à sua API:
Auth0 Express Sample
- Defina seu valor de identificador:
https://express.sample
- Deixe o algoritmo de assinatura como
, pois é a melhor opção do ponto de vista de segurança.RS256
Identificadores são strings únicas que ajudam a Auth0 a diferenciar suas APIs. Recomendamos o uso de URLs para facilitar a criação de identificadores únicos de maneira previsível; no entanto, a Auth0 nunca chama essas URLs.
🛠 Com esses valores preenchidos, clique no botão "Create". Mantenha esta página aberta, pois você precisará de alguns de seus valores na próxima seção.
Adicione as variáveis de configuração da Auth0 à Express
🛠 Crie um arquivo
.env
para o servidor da API no diretório auth0-express-js-sample:
touch .env
🛠 Preencha este arquivo
auth0-express-js-sample/.env
da seguinte forma:SERVER_PORT=6060 CLIENT_ORIGIN_URL=http://localhost:4040 AUTH0_AUDIENCE= AUTH0_DOMAIN=
🛠 Volte para a página da API no dashboard da Auth0 e siga estas etapas para obter a Auth0 Audience:
- 🛠 Clique na guia "Settings".
- 🛠 Localize o campo "Identifier" e copie seu valor.
- 🛠 Cole o valor "Identifier" como o valor de
no arquivoAUTH0_AUDIENCE
..env
Agora, siga estas etapas para obter o valor do Auth0 Domain:
- 🛠 Clique na aba "Test".
- 🛠 Localize a seção chamada "Asking Auth0 for tokens from my application".
- 🛠 Clique na guia cURL para mostrar uma requisição
simulada.POST
- 🛠 Copie seu domínio Auth0, que faz parte do valor do parâmetro
:--url
.nome-do-tenant.regiao.auth0.com
- 🛠 Cole o valor do domínio Auth0 como o valor de
no arquivoAUTH0_DOMAIN
..env
Dicas para obter o Auth0 Domain
- O Auth0 Domain é a substring entre o protocolo,
e o caminhohttps://
./oauth/token
- O Auth0 Domain segue este padrão:
.nome-do-tenant.regiao.auth0.com
- O subdomínio da região (
,au
ouus
) é opcional. Alguns domínios Auth0 não o possuem.eu
- Clique na imagem acima, por favor, se tiver alguma dúvida de como obter o valor do Auth0 Domain.
🛠 Com os valores de configuração
.env
definidos, rode o servidor da API executando o seguinte comando:npm start
Configure o React para se conectar com a Express API
🛠 Volte para o diretório do projeto
auth0-react-sample
que armazena sua aplicação React.🛠 Localize o arquivo
auth0-react-sample/.env
e adicione seus valores Auth0 Audience e Server URL a ele:REACT_APP_AUTH0_DOMAIN=YOUR-AUTH0-DOMAIN REACT_APP_AUTH0_CLIENT_ID=YOUR-AUTH0-APP-CLIENT-ID REACT_APP_AUTH0_AUDIENCE=https://express.sample REACT_APP_SERVER_URL=http://localhost:6060
🛠 O valor do
REACT_APP_AUTH0_AUDIENCE
é o mesmo que AUTH0_AUDIENCE
que você colocou no arquivo auth0-express-js-sample/.env
.Por que todas as variáveis no arquivo React .env
começam com REACT_APP_
?
.env
REACT_APP_
create-react-app
exige que você crie variáveis de ambiente personalizadas começando com REACT_APP_
ao usar um arquivo .env
. create-react-app
irá ignorar quaisquer outras variáveis, exceto NODE_ENV
.O prefixo
REACT_APP_
reduz o risco de exposição acidental de uma chave privada da sua máquina que pode ter o mesmo nome de uma variável do arquivo .env
.Sua aplicação React precisa passar um token de acesso ao chamar uma API de destino para acessar recursos protegidos. Você pode solicitar um token de acesso em um formato que a API pode verificar passando as propriedades da audiência e escopo para
Auth0Provider
.Quaisquer mudanças feitas nas variáveis de ambiente React exigem que você reinicie o servidor de desenvolvimento se ele estiver em execução.
🛠 Reinicie sua aplicação React para que ela possa usar os novos valores que você definiu em
auth0-react-sample/.env
.🛠 Atualize o arquivo
auth0-provider-with-history.js
no diretórioauth0-react-sample/src/auth
para adicionar a propriedade audience
:// src/auth/auth0-provider-with-history.js import React from 'react'; import { useHistory } from 'react-router-dom'; import { Auth0Provider } from '@auth0/auth0-react'; const Auth0ProviderWithHistory = ({ children }) => { const history = useHistory(); const domain = process.env.REACT_APP_AUTH0_DOMAIN; const clientId = process.env.REACT_APP_AUTH0_CLIENT_ID; const audience = process.env.REACT_APP_AUTH0_AUDIENCE; const onRedirectCallback = (appState) => { history.push(appState?.returnTo || window.location.pathname); }; return ( <Auth0Provider domain={domain} clientId={clientId} redirectUri={window.location.origin} onRedirectCallback={onRedirectCallback} audience={audience} > {children} </Auth0Provider> ); }; export default Auth0ProviderWithHistory;
Por que o valor de audiência da Auth0 é o mesmo para as duas aplicações? Auth0 usa o valor da propriedade
audience
para determinar qual servidor de recursos (API) o usuário está autorizando sua aplicação React a acessar. É como um número de telefone. Você deseja garantir que sua aplicação React "envie o texto para a API certa".As ações que sua aplicação React pode executar na API dependem dos escopos que seu token de acesso contém, que você define como o valor de uma propriedade
scope
em Auth0Provider
.Lembra daquela tela que você viu quando fez login pela primeira vez com Auth0 pedindo permissão para acessar as informações de seu perfil? Sua aplicação React fará a requisição da autorização do usuário para acessar os escopos requisitados e o usuário aprovará ou negará a requisição. Você pode ter visto algo semelhante ao compartilhar seus contatos ou fotos de uma plataforma de mídia social com uma aplicação de terceiros.
Quando você não passa uma propriedade
scope
para Auth0Provider
como no exemplo acima, o SDK da Auth0 para React usa por padrão os escopos do OpenID Connect: openid profile email
.
: Este escopo informa ao servidor de autorização Auth0 que o cliente está fazendo uma requisição OpenID Connect (OIDC) para verificar a identidade do usuário. OpenID Connect é um protocolo de autenticação.openid
: este valor de escopo requer acesso às informações de perfil padrão do usuário, comoprofile
,name
enickname
.picture
: este valor de escopo requer acesso às informações deemail
eemail
.email_verified
Os detalhes dos escopos do OpenID Connect vão para o ID token. No entanto, você pode definir escopos de API personalizados para implementar o controle de acesso. Você identificará esses escopos personalizados nas chamadas que suas aplicações clientes fazem para essa API. Auth0 inclui escopos de API no token de acesso como o valor de declaração de scope.
Os conceitos sobre escopos ou permissões de API são melhor abordados em um tutorial de API Auth0, como “Use TypeScript to Create a Secure API with Node.js and Express: Role-Based Access Control”.
🛠 Atualize
src/views/external-api.js
da seguinte forma:// src/views/external-api.js import React, { useState } from 'react'; import { useAuth0 } from '@auth0/auth0-react'; const ExternalApi = () => { const [message, setMessage] = useState(""); const serverUrl = process.env.REACT_APP_SERVER_URL; const { getAccessTokenSilently } = useAuth0(); const callApi = async () => { try { const response = await fetch(`${serverUrl}/api/messages/public-message`); const responseData = await response.json(); setMessage(responseData.message); } catch (error) { setMessage(error.message); } }; const callSecureApi = async () => { try { const token = await getAccessTokenSilently(); const response = await fetch( `${serverUrl}/api/messages/protected-message`, { headers: { Authorization: `Bearer ${token}`, }, } ); const responseData = await response.json(); setMessage(responseData.message); } catch (error) { setMessage(error.message); } }; return ( <div className="container"> <h1>External API</h1> <p> Use these buttons to call an external API. A chamada API protegida tem um token de acesso em seu cabeçalho de autorização. O servidor API irá validar o token de acesso usando o valor Auth0 Audience. </p> <div className="btn-group mt-5" role="group" aria-label="External API Requests Examples" > <button type="button" className="btn btn-primary" onClick={callApi}> Get Public Message </button> <button type="button" className="btn btn-primary" onClick={callSecureApi} > Get Protected Message </button> </div> {message && ( <div className="mt-5"> <h6 className="muted">Result</h6> <div className="container-fluid"> <div className="row"> <code className="col-12 text-light bg-dark p-4">{message}</code> </div> </div> </div> )} </div> ); }; export default ExternalApi;
O que está acontecendo agora no componente
ExternalApi
?- Você adiciona um método
que executa uma requisição de API pública.callApi()
- Você adiciona um método
que executa uma requisição de API segura da seguinte maneira:callSecureApi()
- (a) Obtenha o token de acesso da Auth0 usando o método
, que fornece à sua aplicação React um novo token de acesso por baixo dos panos sem exigir que o usuário efetue login novamente.getAccessTokenSilently
- (b) Passe esse token de acesso como uma credencial no cabeçalho de autorização (bearer) da requisição.
- (a) Obtenha o token de acesso da Auth0 usando o método
- Use o hook do React
para atualizar a interface do usuário sempre que qualquer uma das chamadas de API descritas for concluída com êxito.useState()
Sua requisição de login anterior não incluía um parâmetro de audiência. Como tal, o React SDK não tem um token de acesso armazenado na memória.
Você não deve armazenar tokens em localStorage
Por quê?
localStorage
Armazenar tokens no local storage do navegador fornece persistência nas atualizações de página e guias do navegador, no entanto, se um invasor puder rodar JavaScript na aplicação de página única (Single Page Application ou SPA em inglês) usando um ataque de script entre sites (XSS), ele poderá recuperar os tokens armazenados no local storage.
Uma vulnerabilidade que leva a um ataque XSS bem-sucedido pode estar no código-fonte da SPA ou em qualquer código JavaScript de terceiros incluído no SPA, como Bootstrap, jQuery ou Google Analytics.
🛠 Efetue logout e login novamente para obter um novo token de acesso do Auth0 que inclui as informações de audiência.
🛠 Visite
e clique em qualquer um dos botões na página da External API para testar as respostas.http://localhost:4040/external-api
Obtenha a mensagem pública
The API doesn't require an access token to share this message.
Obtenha a mensagem protegida
The API successfully validated your access token.
Conclusão
Você implementou a autenticação de usuário no React para identificar seus usuários, obter informações de perfil de usuário e controlar o conteúdo que seus usuários podem acessar protegendo rotas e recursos de API.
Este tutorial mostrou o caso de uso de autenticação mais comum para uma aplicação React: login e logout simples. No entanto, a Auth0 é uma plataforma extensível e flexível que pode te ajudar a chegar mais longe. Se você tiver um caso de uso mais complexo, verifique os Auth0 Architecture Scenarios para saber mais sobre os cenários de arquitetura típicos que identificamos ao trabalhar com clientes na implementação da Auth0.
Num próximo tutorial, vamos cobrir padrões e ferramentas de autenticação avançados, como usar um pop-up em vez de um redirecionamento para fazer login de usuários, adicionar permissões a ID tokens, usar metadados para aprimorar perfis de usuário e muito mais.
Comente o que você achou deste tutorial. Obrigado pela leitura.