close icon
Node

O Guia Completo de Autenticação de Usuário em Node.js com Auth0

Aprenda como adicionar autenticação de usuário em aplicações Web Node.js com Express usando middleware.

December 22, 2022

Procure o emoji 🛠️ se quiser passar pelo conteúdo enquanto se concentra nas etapas de criação.

Esse tutorial demonstra como proteger uma aplicação Node.js construída com o framework Express implementando autenticação de usuário. Você vai melhorar uma aplicação Node.js inicial para praticar os seguintes conceitos de segurança:

  • Adicionar login e logout de usuário.
  • Recuperar informações de usuário.
  • Proteger as rotas da aplicação.
  • Chamar endpoints protegidos de uma API.

Este tutorial usa a biblioteca de OpenID Connect da Auth0 para Express para proteger as aplicações Express. Essa biblioteca dá às pessoas desenvolvedoras de Node.js uma alternativa ao Passport.js. O OpenID Connect para Express permite adicionar autenticação de usuário a aplicações Express usando as melhores práticas de segurança enquanto escreve menos código.

⚠️ Se você ainda precisar usar o Passport.js para proteger sua aplicação Express, consulte o tutorial Node.js e Autenticação Express usando o Passport (em inglês).

Exemplo de uma aplicação com Auth0 Express

Como a Auth0 funciona?

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 Express da Auth0 (em inglês) para começar a usar a autenticação de usuário em Express em apenas alguns minutos.

Obtenha a Aplicação Inicial

Criamos um projeto inicial para te ajudar a aprender os conceitos de segurança do Node.js por meio da prática. O projeto inicial usa Bootstrap com um tema personalizado para cuidar do estilo e do layout da sua aplicação. Você pode se concentrar em construir componentes Express para proteger sua aplicação.

🛠 Dessa forma, clone o repositório auth0-express-pug-sample em seu branch starter para começar:

git clone -b starter git@github.com:auth0-blog/auth0-express-pug-sample.git

🛠 Depois de clonar o repositório, torne auth0-express-pug-sample seu diretório atual:

cd auth0-express-pug-sample

🛠 Instale as dependências do projeto Node.js:

npm install

🛠 Crie um arquivo .env dentro do diretório do projeto:

touch .env

🛠 Preencha o arquivo .env assim:

DEV_PORT=4041
PROD_PORT=4040

Para simplificar seu fluxo de desenvolvimento em Node.js, este projeto usa o nodemon para reiniciar o servidor e browser-sync para recarregar o navegador sempre que os arquivos de código fonte relevantes forem alterados.

🛠 Execute o seguinte comando para iniciar o servidor Node.js:

npm run dev

Você pode simular o comportamento de frameworks front-end quando são recarregados em execução, como React e Angular em templates Express usando o Browsersync. O navegador será atualizado automaticamente sempre que o código-fonte for alterado: por exemplo, quando você modifica uma regra CSS ou altera o valor de retorno de uma função.

🛠 Abra uma janela de terminal separada e execute o seguinte comando para servir a interface do usuário da sua aplicação Express:

npm run ui

O Browsersync abre automaticamente uma nova janela apresentando a interface de usuário da sua aplicação. Se não, abra http://localhost:4040/.

Conecte O Express Com a Auth0

A melhor parte da plataforma Auth0 é a simplicidade para começar a usá-la, seguindo estas etapas:

Se inscreva e crie uma Aplicação Auth0

Uma conta gratuita oferece:


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 escolha o tipo da aplicação.

  • Name: (Nome)
Auth0 Express
  • Application Type (Tipo da aplicação): Regular Web Applications

🛠 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 ajudar o Express e a Auth0 a se comunicarem.

Qual é a relação entre Auth0 Tenants e aplicações Auth0?

Digamos que você tenha uma aplicação Express de compartilhamento de fotos chamado “Noddit”. Você então criaria um Auth0 tenant chamado noddit.

Agora, digamos que o Noddit 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.

Crie uma ponte de comunicação entre Express 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 Express 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. 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/callback

O valor acima é a URL que 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 Auth0 pode usar para redirecionar seus usuários depois que eles fizerem logout.

🛠 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 Express

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 Express use a ponte de comunicação que você criou.

O que exatamente é um domínio Auth0 e um ID de cliente Auth0?

Domain

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.

Auth0 também oferece suporte a domínios personalizados para para permitir que o Auth0 faça o trabalho pesado de autenticação para você sem comprometer sua experiência de branding.

ID de Cliente

A Auth0 atribui um ID de cliente (Client ID) a cada aplicação, 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 Express 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 tiverem autorização. 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 segredo, pode se passar pela sua aplicação e acessar recursos protegidos.

🛠 Abra o arquivo .env do diretório do projeto auth0-express-pug-sample e atualize-o da seguinte forma:

DEV_PORT=4041
PROD_PORT=4040
AUTH0_ISSUER_BASE_URL=https://<AUTH0_DOMAIN>/
AUTH0_CLIENT_ID=

🛠 Para o valor AUTH0_ISSUER_BASE_URL, &lt;AUTH0_DOMAIN> é o valor do seu Domain nas "Settings". Certifique-se de manter a barra no final para esse valor.

🛠 AUTH0_CLIENT_ID é o seu Client ID em "Settings".

Configurações da aplicação Auth0 no Auth0 Dashboard

Essas variáveis permitem que sua aplicação Express se identifique como uma parte autorizada para interagir com o servidor de autenticação Auth0.

Conexão Auth0 e Express

Você concluiu a configuração de um serviço de autenticação que sua aplicação Express pode consumir. Agora só falta continuar construindo o projeto ao longo deste guia, adicionando componentes para acionar e gerenciar o fluxo de autenticação.

Fique à vontade para se aprofundar 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 OpenID Connect Para Express

🛠 Você precisa seguir estas etapas para integrar a biblioteca OpenID Connect com sua aplicação Express.

Instale o OpenID Connect para Express

🛠 Execute o seguinte comando:

npm install express-openid-connect

Configure o OpenID Connect para Express

🛠 Abra o arquivo .env novamente e adicione valores em BASE_URL e SESSION_SECRET nele:

DEV_PORT=4041
PROD_PORT=4040
AUTH0_ISSUER_BASE_URL=<...>
AUTH0_CLIENT_ID=<...>
BASE_URL=http://localhost:4040
SESSION_SECRET=

O valor BASE_URL é a URL onde sua aplicação é servida.

O valor SESSION_SECRET é o segredo usado para assinar o cookie de ID de sessão, que pode ser uma string para um único segredo ou um vetor com vários segredos.

🛠️ Execute o seguinte comando para gerar uma string adequada para o segredo da sessão:

node -e "console.log(crypto.randomBytes(32).toString('hex'))"

🛠️ Copie e cole a saída do comando acima como o valor de SESSION_SECRET em .env.

🛠️ Para que sua aplicação reconheça essas novas variáveis de ambiente, você precisa reiniciar o servidor Node.js. Localize a janela do terminal onde você executou npm run dev anteriormente, pare-o e execute-o novamente.

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, a 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 Express não é muito diferente da segurança de uma boate.

Se os usuários quiserem acessar uma rota protegida da sua aplicação, a 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 Express 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.

A biblioteca OpenID Connect para Express fornece a rota auth para anexar rotas de autenticação à sua aplicação. Você não precisará implementar controladores /login ou /logout, o OpenID Connect para Express faz isso para você.

Agora você precisa inicializar, configurar e integrar express-openid-connect com sua aplicação Express.

🛠 Abra o arquivo src/index.js e atualize a seção Required External Modules para importar auth:

// src/index.js

/**
 * Required External Modules
 */

const express = require('express');
const path = require('path');
const { auth } = require('express-openid-connect');

🛠 Em seguida, atualize a seção App Configuration para inicializar e usar auth como uma função de middleware do Express:

// src/index.js

/**
 *  App Configuration
 */

app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');
app.use(express.static(path.join(__dirname, '..', 'public')));
app.use(
  auth({
    issuerBaseURL: process.env.AUTH0_ISSUER_BASE_URL,
    baseURL: process.env.BASE_URL,
    clientID: process.env.AUTH0_CLIENT_ID,
    secret: process.env.SESSION_SECRET,
    authRequired: false,
    auth0Logout: true,
  }),
);

Você está adicionando duas propriedades adicionais, authRequirede auth0Logout. O que essas propriedades estão fazendo?

authRequired é uma propriedade booleana que configura o OpenID Connect para Express para exigir autenticação para todas as rotas quando você o define como true. Para este projeto, você terá uma mistura de rotas públicas e protegidas. Dessa forma, você define essa propriedade como false.

auth0Logout é outro valor booleano que habilita o recurso de logout Auth0, que permite um usuário fazer logout da sessão Auth0. Ao implementar a funcionalidade de logout em uma aplicação, normalmente há três camadas de sessão que você precisa considerar:

  • Camada de sessão da aplicação
  • Camada de sessão Auth0
  • Camada de sessão do provedor de identidade

Por exemplo, se um de seus usuários fez login usando o Google, você pode configurar seu serviço de autenticação Auth0 para que ele faça logout da aplicação, da sessão Auth0 ou do próprio Google. Confira o documento “Logout" (em inglês) para saber mais detalhes sobre a arquitetura do logout do usuário.

Para esta aplicação, você fará logout dos usuários da camada de sessão Auth0.

A biblioteca OpenID Connect para Express está configurada. Tudo pronto para implementar a autenticação do usuário na próxima seção.

Adicione Autenticação De Usuários

Ao longo deste guia, você usará mixins Pug para implementar a interface do usuário (UI) da aplicação seguindo uma arquitetura baseada em componentes. Cada mixin atuará como um componente de UI, tornando-se uma peça reutilizável que você pode criar e manter isoladamente.

Você precisa criar componentes de UI para que seus usuários acionem eventos de autenticação: login, logout e inscrição.

O OpenID Connect para Express cria um namespace oidc no objeto req da sua aplicação. Nesse namespace, a biblioteca armazena métodos e dados de autenticação, como um objeto user para armazenar informações de perfil do usuário e um método login para personalizar a experiência de login do usuário. Você explorará o objeto oidc nas próximas seções.

Crie um botão de login

🛠 Crie um arquivo login-button.pug dentro do diretório src/components/:

touch src/components/login-button.pug

🛠 Crie um mixin para representar um componente de botão de login em src/components/login-button.pug assim:

mixin login-button()
  button(
    class="btn btn-primary btn-block",
    onclick="window.location='/login'"
  ) Log In

Por baixo dos panos, o OpenID Connect para Express cria uma rota /login para a sua aplicação Express. Quando o usuário clica neste botão, sua aplicação Express solicita do usuário que faça autenticação e dê consentimento para que sua aplicação Express acesse determinados dados em nome deste usuário. Em sua arquitetura atual, isso significa que sua aplicação Express 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 personalizar a experiência de login usando o método req.oidc.login() no controlador Express. Por exemplo, você pode passar opções para este método redirecionar usuários a uma página de login universal Auth0 otimizada para se inscrever na sua aplicação Express.

Crie um botão de inscrição

Você pode fazer os usuários acessarem diretamente uma página de inscrição em vez de uma página de login criando um controlador de rota /sign-up.

🛠 Para começar, abra o arquivo src/index.js. Localize a seção Routes Definitions. Nesta seção, existem diferentes subseções que definem rotas para cada recurso da sua aplicação Web Express. Localize a subseção > Authentication e atualize-a da seguinte forma:

// src/index.js

/**
 * Routes Definitions
 */

// > Other route subsections...

// > Authentication

app.get('/sign-up', (req, res) => {
  res.oidc.login({
    authorizationParams: {
      screen_hint: 'signup',
    },
  });
});

Você cria um controlador de rota /sign-up, onde você acessa o método res.oidc.login(). Esse método usa algumas LoginOptions para personalizar o comportamento da experiência de login do usuário.

Aqui, você sobrescrever o authorizationParams padrão, que são parâmetros de URL que o OpenID Connect para Express usa ao redirecionar usuários para Auth0 para fazer login.

Você pode passar novos valores para alterar o que o servidor de autorização Auth0 retorna dependendo do seu caso de uso. Em seu controlador /sign-up, você especifica a propriedade screen_hint=signup como um parâmetro de autorização para levar os usuários a um formulário de inscrição.

{
  authorizationParams: {
    screen_hint: "signup",
  },
}

Agora, crie um botão de inscrição para acionar esse evento solicitando a rota /sign-up.

🛠 Crie um arquivo signup-button.pug no diretório src/components/:

touch src/components/signup-button.pug

🛠 Preencha src/components/signup-button.pug assim para definir um mixin signup-button:

mixin signup-button()
  button(
    class="btn btn-primary btn-block",
    onclick="window.location='/sign-up'"
  ) Sign Up

O uso do recurso de inscrição exige que você habilite a nova experiência de login universal Auth0 em seu tenant.

🛠 Abra a seção Login Universal do Auth0 Dashboard e escolha a opção "New" na subseção "Experience".

opções da Auth0 Universal Login Experience

🛠 Role para baixo e clique no botão "Save changes".

A diferença entre a experiência de usuário em fazer login ou se inscrever ficará mais evidente quando você integrar esses componentes à aplicação Express e vê-los em ação. Você fará isso nas próximas seções

Crie um botão de logout

🛠 Crie um logout-button.pug no diretório src/components/:

touch src/components/logout-button.pug

🛠 Preencha o arquivo src/components/logout-button.pug assim:

mixin logout-button()
  button(
    class="btn btn-danger btn-block",
    onclick="window.location='/logout'"
  ) Log Out

A rota /logout criada pelo OpenID Connect para Express chama o método req.oidc.logout() por baixo dos panos. Este método limpa a sessão da aplicação e redireciona para o endpoint Auth0 /v2/logout para limpar a sessão Auth0. Assim como no método de login, você pode passar LogoutOptions para req.oidc.logout() para personalizar seu comportamento.

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ê fizer o deploy da sua aplicação Express 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.

Leia mais sobre como funciona o Logout na Auth0 (em inglês).

Integre os botões de login e logout

Vamos envolver os mixins login-button e logout-button em um chamado authentication-button.

🛠 Crie um arquivo authentication-button.pug no diretório src/components/:

touch src/components/authentication-button.pug

🛠 Preencha src/components/authentication-button.pug com o seguinte código:

include ./login-button
include ./logout-button

mixin authentication-button(isAuthenticated)
  if isAuthenticated
    +logout-button
  else
    +login-button

isAuthenticated é um valor booleano exposto pelo objeto req.oidc. Seu valor é true quando a Auth0 autenticou o usuário e false quando não o fez.

Existem algumas vantagens em usar este wrapper de mixin authentication-button:

Você pode construir interfaces flexíveis. authentication-button 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 os mixins login-button e logout-button separados para os casos em que você precise de sua funcionalidade de forma isolada. Por exemplo, você pode ter um botão de logout em uma página que somente usuários autenticados podem ver.

Você pode construir interfaces extensíveis. Você pode facilmente trocar o mixin login-button por signup-button em authentication-button para criar uma opção de "inscrever-se/fazer logout". Você também pode envolver a opção "inscrever-se/fazer logout" em um mixin new-authentication-button.

Você pode construir interfaces declarativas. Usando authentication-button, você pode adicionar a funcionalidade de login e logout ao seu componente de barra de navegação, 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.pug no diretório src/components/:

touch src/components/auth-nav.pug

🛠 Preencha src/components/auth-nav.pug assim:

include ./authentication-button

mixin auth-nav(isAuthenticated)
  div(class="navbar-nav ml-auto")
    +authentication-button(isAuthenticated)

isAuthenticated aparece de novo. De onde vem esse valor? Você vai descobrir em breve!

🛠 Finalmente, abra o arquivo nav-bar.pug no diretório src/components/ e atualize-o assim:

include ./main-nav
include ./auth-nav

mixin nav-bar(activeRoute)
  div(class="nav-container mb-3")
    nav(class="navbar navbar-expand-md navbar-light bg-light")
      div(class="container")
        div(class="navbar-brand logo")
        +main-nav(activeRoute)
        +auth-nav(isAuthenticated)

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 nav-bar.

Mais uma vez, isAuthenticated aparece. A biblioteca OpenID Connect para Express define esse valor no método req.oidc.isAuthenticated(). Seu valor de retorno é essencial para que a autenticação funcione corretamente em sua aplicação Express.

Como você passa dados de um controlador para um modelo no Express?

Em aplicações web Express, você tem acesso a um fluxo de dados unidirecional do controlador de rota para o modelo. Como tal, cada controlador de rota que renderiza um modelo que depende de isAuthenticated deve passar esse valor.

No entanto, passar um valor manualmente para um modelo em cada controlador de rota não é apenas tedioso, mas propenso a erros. O que você pode fazer é disponibilizar o valor como um valor local para todos os modelos Pug.

🛠 Atualize a seção App Configuration no arquivo src/index.js dessa forma:

// src/index.js

/**
 *  App Configuration
 */

app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');

app.use(express.static(path.join(__dirname, '..', 'public')));

app.use(
  auth({
    issuerBaseURL: process.env.AUTH0_ISSUER_BASE_URL,
    baseURL: process.env.BASE_URL,
    clientID: process.env.AUTH0_CLIENT_ID,
    secret: process.env.SESSION_SECRET,
    authRequired: false,
    auth0Logout: true,
  }),
);

app.use((req, res, next) => {
  res.locals.isAuthenticated = req.oidc.isAuthenticated();
  next();
});

Você define res.locals em um manipulador de função de middleware. Este objeto permite que você passe dados pela sua Aplicação Express. Todos os seus modelos de Pug podem acessar suas propriedades (como isAuthenticated) diretamente. Como req.oidc.isAuthenticated() é um método, você deve executá-lo para obter seu valor.

Há uma ressalva sobre o uso de res.locals: esses valores vivem apenas em uma requisição individual. Assim que o ciclo de requisição-resposta é concluído, os valores desaparecem. Isso não é um problema para sua aplicação, pois cada vez que um usuário solicita uma rota do navegador, o ciclo de requisição-resposta começa novamente.

Leia mais detalhes sobre res.locals no StackOverflow.

🛠 Vá em frente e tente fazer o login. Sua aplicação Express 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.

Formulário da nova experiência do Login Universal Auth0

Experimento: Use o mixin signup-button

Troque o mixin login-button pelo mixin signup-button na condição definida no mixin authentication-button:

include ./signup-button
include ./logout-button

mixin authentication-button(isAuthenticated)
if isAuthenticated
  +logout-button
else
  +signup-button

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 Express.

Experimente isso!

Nova página de inscrição na Experiência de Login Universal Auth0

Depois de concluir esse teste, troque signup-button por login-button para continuar com o restante deste guia.

include ./login-button
include ./logout-button

mixin authentication-button(isAuthenticated)
if isAuthenticated
  +logout-button
else
  +login-button

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.

🛠 Clique na aba Profile e depois clique no botão "Log Out".

Observe que o Express desconectou você, mas em vez de levá-lo de volta à rota /profile, ele o levou de volta à rota /, a página inicial.

🛠 Clique na aba Profile e agora clique no botão "Log In".

Desta vez, o Express te leva novamente de volta à página inicial / depois de fazer login. Como usuário, você espera acessar a página /profile depois de fazer login, certo? Afinal, seu sistema de autenticação está agindo como um bouncer. O bouncer não leva as pessoas de volta à entrada da boate depois de apresentarem seus RGs. O bouncer permite que essas pessoas passem e acessem a sala VIP ou qualquer sala que o bouncer esteja protegendo.

Por que esse redirecionamento da página inicial está acontecendo?

Esta aplicação web Express está usando rotas estáticas para renderizar sua interface de usuário. Você mapeia uma ação da interface do usuário com um endpoint ou controlador do servidor. Este mapeamento é fixo até então.

O controlador de rota /login que a biblioteca OpenID Connect para Express criou para você tem um valor fixo para o caminho ao qual a Auth0 deve retornar os usuários após eles efetuarem login. Esse valor padrão é a raiz da URL do servidor, /.

No entanto, e se a página /profile tivesse recursos públicos e protegidos? Em um cenário como esse, qualquer pessoa pode visitar a página /profile para ler suas informações públicas. Em seguida, os usuários podem fazer login para ler as informações protegidas. A melhor experiência do usuário é que os usuários retornem à página /profile após efetuarem login, não à página inicial.

Uma maneira de corrigir esse redirecionamento da página inicial é criar uma rota dedicada para cada tipo de login e logout:

GET /sign-up-profile

GET /sign-up-external-api

GET /login-profile

GET /login-external-api

GET /logout-profile

GET /logout-external-api

No entanto, esse método não vai escalar nada bem. Imagine se você tivesse mais de 10 páginas diferentes que exigem uma experiência de login tranquila.

Seria melhor criar uma única rota dinâmica que pudesse lidar com diferentes "tipos" de ações de login e logout:

GET /sign-up/:page

GET /login/:page

GET /logout/:page

Como a rota /sign-up se comporta de maneira muito parecida com a rota /login, você também está aprimorando essa rota - caso queira usar o botão "Inscrever-se" em sua aplicação.

Em seguida, você pode pegar esse parâmetro :page e usá-lo para dizer à Auth0 para voltar os usuários para serverUrl/page depois que eles fizerem login ou logout.

Para implementar facilmente esses novos controladores de rota de autenticação, você pode aproveitar a propriedade activeRoute que está passando de seus controladores de rota para seus modelos. Dê uma olhada no controlador de rota /profile, por exemplo:

app.get('/profile', (req, res) => {
  res.render('profile', { activeRoute: req.originalUrl });
});

Você passa este objeto { activeRoute: req.originalUrl } em todos os controladores de rota. Recentemente, você aprendeu como aproveitar res.locals para disponibilizar o status de autenticação do usuário para toda a aplicação Express. Você pode fazer o mesmo para a propriedade activeRoute.

🛠 As etapas a seguir mostrarão como criar rotas de autenticação dinâmicas. No entanto, se você deseja que o Express redirecione todos os usuários que efetuam logout para a página inicial, pode deixar sua aplicação como está.

🛠 Atualize a seção App Configuration no arquivo src/index.js da seguinte forma:

// src/index.js

/**
 *  App Configuration
 */

app.set("views", path.join(__dirname, "views"));
app.set("view engine", "pug");

app.use(express.static(...));

app.use(
  auth({...})
);

app.use((req, res, next) => {
  res.locals.isAuthenticated = req.oidc.isAuthenticated();
  res.locals.activeRoute = req.originalUrl;
  next();
});

Agora você define outra variável local que todos os modelos Pug podem acessar: res.locals.activeRoute. Você não precisa mais passar activeRoute para seus modelos de cada controlador.

🛠 Localize a seção Routes Definitions no arquivo src/index.js. Atualize as subseções > Home, > Profile, e > External API assim:

// src/index.js

/**
 * Routes Definitions
 */

// > Home

app.get('/', (req, res) => {
  res.render('home');
});

// > Profile

app.get('/profile', (req, res) => {
  res.render('profile');
});

// > External API

app.get('/external-api', (req, res) => {
  res.render('external-api');
});

🛠 Agora você precisa criar os controladores de rota sign-up/:page, login/:page e logout/:page. Volte para a seção Routes Definitions no arquivo src/index.js. Atualize a subseção > Authentication assim:

// src/index.js

/**
 * Routes Definitions
 */

// > Authentication

app.get('/sign-up/:page', (req, res) => {
  const { page } = req.params;

  res.oidc.login({
    returnTo: page,
    authorizationParams: {
      screen_hint: 'signup',
    },
  });
});

app.get('/login/:page', (req, res) => {
  const { page } = req.params;

  res.oidc.login({
    returnTo: page,
  });
});

app.get('/logout/:page', (req, res) => {
  const { page } = req.params;

  res.oidc.logout({
    returnTo: page,
  });
});

Agora, você precisa atualizar seus botões de login e logout para usar esses controladores de rota personalizados em vez dos que vem padrão criados pelo Express OpenID Connect.

🛠 Atualize src/components/signup-button.pug dessa forma:

mixin signup-button()
  button(
    class="btn btn-primary btn-block",
    onclick=`window.location='/sign-up/${activeRoute}'`
  ) Sign Up

🛠 Atualize src/components/login-button.pug dessa forma:

mixin login-button()
  button(
    class="btn btn-primary btn-block",
    onclick=`window.location='/login/${activeRoute}'`
  ) Log In

🛠 Atualize src/components/logout-button.pug dessa forma:

mixin logout-button()
  button(
    class="btn btn-danger btn-block",
    onclick=`window.location='/logout/${activeRoute}'`
  ) Log Out

activeRoute está disponível em qualquer modelo sem a necessidade de passá-lo de mixin para mixin.

🛠 Visite a página "Profile" e tente fazer o login ou logout.

Se você fizer login, observe que você volta para a página "Profile" depois de fazer login usando a página de login universal Auth0.

Se você fizer logout, receberá um erro!

Mensagem de erro no logout da Auth0

Por que você está recebendo um erro ao fazer logout da página /profile?

Se você clicar no link "See details for this error" na página de erro, saberá que o erro está relacionado a um invalid_request: O parâmetro querystring"returnTo" "http://localhost:4040/profile" não está definido como uma URL válida em "Allowed Logout URLs".

Durante a seção de configuração da Auth0 deste guia, você definiu "Allowed Logout URLs" para a aplicação Auth0 que representa sua aplicação Web Express na plataforma Auth0:

Allowed Logout URLs

http://localhost:4040

Auth0 só pode redirecionar seus usuários depois que eles fizerem logout das URLs listadas nesse campo. Assim, você precisa adicionar os caminhos /profile e /external-api a ele.

🛠 Volte para a seção "Applications" no Auth0 Dashboard. Selecione sua aplicação"Auth0 Express Sample" e clique na guia "Settings".

🛠 Localize Allowed Logout URLs atualize-as assim:

http://localhost:4040,
http://localhost:4040/profile,
http://localhost:4040/external-api

🛠 Role para baixo e clique em "Save Changes".

🛠 Volte para a interface de usuário da aplicação no navegador. Visite as páginas "Profile" ou "External API". Atualize a página e tente fazer login e logout. Agora você deve permanecer na mesma página depois que qualquer ação for concluída sem erros.

Nesta seção, você aprendeu como usar os controladores de rota embutidos /login e /logout expostos pela biblioteca OpenID Connect para Express. Você também aprendeu a criar controladores de autenticação personalizados para melhorar a experiência do usuário em sua aplicação e para acomodar diferentes casos de uso.

Na próxima seção, você aprenderá como recuperar e exibir informações de perfil de usuário em sua interface de usuário.

Recupere Informações Do Usuário

Você pode usar dados de perfil armazenados em seu banco de dados de usuário Auth0 para personalizar a interface de usuário da sua aplicação Express. A biblioteca OpenID Connect para Express expõe esses dados de perfil no objeto req.oidc.user. Algumas das informações do usuário disponíveis incluem o nome, apelido, foto e e-mail do usuário conectado.

Como você pode usar req.oidc.user para criar uma página de perfil para seus usuários?

🛠 Atualize o controlador de rota /profile na seção Routes Definitions > Profile no arquivo src/index.js dessa forma:

// src/index.js

/**
 * Routes Definitions
 */

// > Profile

app.get('/profile', (req, res) => {
  res.render('profile', {
    user: req.oidc.user,
  });
});

🛠 Depois, atualize o modelo /profile definido em src/views/profile.pug assim:

extends ../components/layout

block content
  if user
    div
      div(class="row align-items-center profile-header")
        div(class="col-md-2 mb-3")
          img(
            class="rounded-circle img-fluid profile-picture mb-3 mb-md-0"
            src=user.picture
            alt="Profile"
          )
        div(class="col-md text-center text-md-left")
          h2 #{user.name}
          p(class="lead text-muted") #{user.email}
      div(class="row")
        pre(class="col-12 text-light bg-dark p-4")
          | #{JSON.stringify(user, null, 2)}

O que está acontecendo no modelo profile?

  • Você obtém o name, picture e email do usuário do objeto user que você passou para o modelo do controlador de rota /profile.
  • Em seguida, você exibe essas três propriedades na interface de usuário. Você apenas renderiza o conteúdo do modelo profile se o objeto user estiver definido.
  • Por fim, você exibe o conteúdo completo do token de ID decodificado em uma caixa de código. Agora você pode ver todas as outras propriedades disponíveis para você usar.
O que é um ID Token?

Depois que um usuário efetua login com sucesso, Auth0 envia um ID token para sua aplicação. 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. O armazenamento em cache de ID tokens pode contribuir para melhorias no desempenho e capacidade de resposta da sua aplicação.

Você pode usar os dados do ID token para personalizar a interface do usuário da sua aplicação. A biblioteca OpenID Connect para Express decodifica o ID token e adiciona as suas informações à propriedade user do namespace req.oidc. Algumas das informações do ID token incluem o nome, apelido, imagem e e-mail do usuário conectado.

O modelo profile renderiza informações do usuário que você pode considerar protegidas. Além disso, a propriedade 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 modelo, http://localhost:4040/profile. Você aprenderá a fazer exatamente isso na próxima seção.

Proteja as Rotas

A biblioteca OpenID Connect para Express expõe uma função de middleware requiresAuth() que você pode usar para exigir que os usuários façam login para acessar uma rota específica. O Express redirecionará para a página de Login Universal Auth0 qualquer usuário que não tenha feito login e tente acessar a rota.

Um lembrete: para requiresAuth() funcionar, você deve definir authRequired como false ao inicializar o Express OpenID Connect usando a função de middleware auth.

🛠 Abra o arquivo src/index.js e atualize a seção Required External Modules dessa forma:

// src/index.js

/**
 * Required External Modules
 */

const express = require('express');
const path = require('path');
const { auth, requiresAuth } = require('express-openid-connect');

Você pode adicionar a função de middleware requiresAuth() como parte do ciclo de solicitação-resposta de cada controlador que deseja proteger — neste caso, /profile e /external-api

🛠 Atualize a subseção Routes Definitions > Profile do arquivo src/index.js assim:

/**
 * Routes Definitions
 */

// > Profile

app.get('/profile', requiresAuth(), (req, res) => {
  res.render('profile', {
    user: req.oidc.user,
  });
});

Agora, quando os usuários que não efetuaram login visitarem uma rota protegida, sua aplicação Express redirecionará esse usuário para a página de login. Após o login do usuário, a Auth0 redirecionará o usuário para a página que ele pretendia acessar antes do login.

Agora você pode testar se /profile exige que os usuários façam login antes de acessá-lo. Faça o log out e tente acessar a página Profile. Se funcionar, o Express redireciona você para fazer o login com Auth0.

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 Express 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 Express. No entanto, sua aplicação pode precisar acessar recursos protegidos de uma API, como contatos, fotos ou histórico de compras.

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 externas seguras a partir do Express?

Sua aplicação Express 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 Express.

git clone git@github.com:auth0-blog/auth0-express-js-sample.git

🛠 Depois de clonar este repositório, torne o diretório auth0-express-js-sample seu diretório atual:

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 o Express e Auth0

Este processo é semelhante a como você conectou o Express à Auth0.

🛠 Vá para a seção APIs no Dashboard da Auth0 e clique no botão "Create API".

🛠 Então, no formulário que 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 RS256, pois é a melhor opção do ponto de vista de segurança.

Formulário de nova API no Auth0 Dashboard

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:

Obtenha a Auth0 Audience para configurar uma API

  1. 🛠 Clique na guia "Settings".
  2. 🛠 Localize o campo "Identifier" e copie seu valor.
  3. 🛠 Cole o valor "Identifier" como o valor de AUTH0_AUDIENCE no arquivo .env.

Agora, siga estas etapas para obter o valor do Auth0 Domain:

Obtenha o Auth0 Domain para configurar uma API

  1. 🛠 Clique na aba "Test".
  2. 🛠 Localize a seção chamada "Asking Auth0 for tokens from my application".
  3. 🛠 Clique na guia cURL para mostrar uma requisição POST de exemplo.
  4. 🛠 Copie seu domínio Auth0, que faz parte do valor do parâmetro --url: nome-do-tenant.regiao.auth0.com.
  5. 🛠 Cole o valor do domínio Auth0 como o valor de AUTH0_DOMAIN no arquivo .env.
Dicas para obter o Auth0 Domain
  • O Auth0 Domain é a substring entre o protocolo, https:// e o caminho /oauth/token.

  • O Auth0 Domain segue este padrão: nome-do-tenant.regiao.auth0.com.

  • O subdomínio da região (au, us ou eu) é opcional. Alguns domínios Auth0 não o possuem.

  • 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 Express para consumir a API de demonstração

Sua aplicação Express precisa passar um token de acesso ao chamar uma API de destino para acessar recursos protegidos. Você pode solicitar um token de acesso do servidor de autorização Auth0 configurando seu middleware auth() para incluir o público da API e um tipo de resposta code. Vamos ver esta configuração auth() como exemplo:

app.use(
  auth({
    authorizationParams: {
      response_type: 'code',
      audience: 'https://api.example.com/products',
    },
  }),
);

Agora, sempre que você configurar auth() para obter um código como seu response_type, você precisa incluir o Client Secret (segredo do cliente) da sua aplicação Auth0.

🛠 Volte para a seção "Applications" do Auth0 Dashboard. Selecione sua aplicação “Auth0 Express Sample" e clique na guia "Settings". Localize o campo "Client Secret".

🛠 Volte para o diretório do projeto auth0-express-pug-sample que armazena sua aplicação Express.

🛠 Localize o arquivo auth0-express-pug-sample/.env e adicione os valores AUTH0_AUDIENCE, SERVER_URL, e CLIENT_SECRET nele:

DEV_PORT=4041
PROD_PORT=4040
AUTH0_ISSUER_BASE_URL=https://<AUTH0-DOMAIN>/
AUTH0_CLIENT_ID=<...>
BASE_URL=http://localhost:4040
SESSION_SECRET=<...>
AUTH0_AUDIENCE=https://express.sample
SERVER_URL=http://localhost:6060
CLIENT_SECRET=

🛠 O valor de AUTH0_AUDIENCE é o mesmo para a aplicação Web Express e para a API Express.

SERVER_URL é a URL onde o servidor da API Express está rodando.

🛠 Use o valor do Client Secret das configurações da aplicação Auth0 como o valor de CLIENT_SECRET.

O segredo do cliente Auth0 é um valor crítico, pois protege seus recursos, concedendo apenas credenciais relacionadas à autenticação na forma de tokens aos solicitantes se eles forem 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 segredo do cliente, pode se passar pela sua aplicação e acessar recursos protegidos.

Juntas, essas variáveis permitem que sua aplicação se identifique como uma parte autorizada para interagir com o servidor de autenticação Auth0.

🛠️ Você precisa reiniciar o servidor Node.js para que sua aplicação reconheça essas novas variáveis de ambiente. Localize a janela do terminal onde você executou o comando npm run dev anteriormente, interrompa-a e execute-a novamente.

Você pode solicitar um token de acesso em um formato que a API possa verificar passando propriedades audience e response_type para o inicializador auth().

🛠 Abra o arquivo src/index.js, localize a seção App Configuration e atualize a inicialização de auth() da seguinte forma:

// src/index.js

/**
 *  App Configuration
 */

app.set("views", path.join(__dirname, "views"));
app.set("view engine", "pug");

app.use(express.static(path.join(__dirname, "..", "public")));

// 👇 Update the mounting and initialization of auth()
app.use(
  auth({
    issuerBaseURL: process.env.AUTH0_ISSUER_BASE_URL,
    baseURL: process.env.BASE_URL,
    clientID: process.env.AUTH0_CLIENT_ID,
    secret: process.env.SESSION_SECRET,
    authRequired: false,
    auth0Logout: true,
    clientSecret: process.env.CLIENT_SECRET,
    authorizationParams: {
      response_type: "code",
      audience: process.env.AUTH0_AUDIENCE,
    },
  })
);

app.use((req, res, next) => {...});

clientSecret vai no mesmo nível que as outras propriedades. No entanto, quando o Express OpenID Connect faz requisições ao servidor de autorização Auth0, ele usa response_type e audience como parâmetros de requisição. Assim, você precisa especificar esses dois valores como propriedades do objeto authorizationParams.

Por que o valor Auth0 Audience é o mesmo para as duas aplicações? Auth0 usa o valor da propriedade audience para determinar qual servidor de recurso (API) o usuário está autorizando o acesso da aplicação Express. É como um número de telefone. Você deseja garantir que sua aplicação Express "envie mensagem para a API correta".

As ações que a sua aplicação Express pode executar na API dependem dos escopos que seu token de acesso contem.

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 Express 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 o objeto authorizationParams, usado para configurar o auth(), a biblioteca OpenID Connect para Express usa por padrão os escopos do OpenID Connect: openid profile email.

  • openid: 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.
  • profile: este valor de escopo requer acesso às informações de perfil padrão do usuário, como name, nickname e picture.
  • email: este valor de escopo requer acesso às informações de email e email_verified.

Os detalhes dos escopos do OpenID Connect vão para o token de ID. No entanto, você pode definir escopos de API personalizados para implementar o controle de acesso. Você os identificará 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".

🛠 Visite a página "External API" e note que existem dois botões para você solicitar recursos da Express Demo API:

  • "Get Public Message" => GET /messages/public-message
  • "Get Protected Message" => GET /messages/protected-message

Qual é o plano para implementar essas chamadas de API em sua aplicação Web Express? Crie mais duas rotas.

Primeiro, você precisará de um pacote para fazer requisições HTTP de seus controladores de rota Express. Para isso vamos usar a biblioteca got you

🛠 Instale got no seu projeto auth0-express-pug-sample:

npm install got

got se autodenomina uma biblioteca de requisição HTTP poderosa e amigável para aplicações Node.js.

🛠 Abra o arquivo src/index.js e atualize a seção Required External Modules da seguinte forma:

// src/index.js

/**
 * Required External Modules
 */

const express = require('express');
const path = require('path');
const { auth, requiresAuth } = require('express-openid-connect');
const got = require('got');

🛠 Em seguida, atualize a subseção Routes Definitions > External API em src/index.js para adicionar duas rotas para lidar com a recuperação de mensagens da API Express:

// src/index.js

/**
 * Routes Definitions
 */

// > External API

app.get('/external-api', (req, res) => {
  res.render('external-api');
});

app.get('/external-api/public-message', async (req, res) => {
  let message;

  try {
    const body = await got(
      `${process.env.SERVER_URL}/api/messages/public-message`,
    ).json();

    message = body.message;
  } catch (e) {
    message = 'Unable to retrieve message.';
  }

  res.render('external-api', { message });
});

app.get('/external-api/protected-message', requiresAuth(), async (req, res) => {
  const { token_type, access_token } = req.oidc.accessToken;
  let message;

  try {
    const body = await got(
      `${process.env.SERVER_URL}/api/messages/protected-message`,
      {
        headers: {
          Authorization: `${token_type} ${access_token}`,
        },
      },
    ).json();

    message = body.message;
  } catch (e) {
    message = 'Unable to retrieve message.';
  }

  res.render('external-api', { message });
});

O que está acontecendo nos controladores de rota da API externa?

  • Nada muda para /external-api. Ela continua sendo a página inicial deste caminho.
  • /external-api/public-message solicita dados de mensagem de um endpoint de API público /api/messages/public-message.
    • Ele armazena a resposta dessa solicitação na variável message, que passa para o modelo external-api.
    • Esta rota não exige login do usuário para acessar a página ou fazer a chamada da API.
  • /external-api/protected-message solicita dados de mensagem de um endpoint de API protegido, /api/messages/protected-message.
    • Ele obtém o token de acesso e seu tipo no req.oidc.accessToken.
    • Ele usa o token de acesso no cabeçalho de autorização da chamada da API protegida.
    • Ele armazena a resposta dessa requisição na variável message, que passa para o modelo external-api.
    • Como essa rota requer um token de acesso válido para fazer a requisição da API protegida, ela usa requiresAuth() para solicitar que o usuário faça login.

O encadeamento do método .json() de got permite obter as respostas do servidor no formato JSON.

🛠 Agora, atualize src/views/external-api.pug da seguinte forma:

extends ../components/layout

block content
  div
    h1 External API
    p
      | Use these buttons to call an external API. The protected API call has an access token in its authorization header. The API server will validate the access token using the Auth0 Audience value.
    div(
      class="btn-group mt-5",
      role="group",
      aria-label="External API Requests Examples"
    )
      button(
        type="button",
        class="btn btn-primary"
        onclick="window.location='/external-api/public-message'"
      ) Get Public Message
      button(
        type="button",
        class="btn btn-primary"
        onclick="window.location='/external-api/protected-message'"
      ) Get Protected Message

    if message
      div(class="mt-5")
        h6(class="muted") Result
        div(class="container-fluid")
          div(class="row")
            code(class="col-12 text-light bg-dark p-4")
              | #{JSON.stringify(message, null, 2)}

O que está acontecendo agora dentro do modelo external-api?

Você aciona chamadas para os controladores de rota /external-api/public-message e /external-api/protected-message do grupo de botões. Se message for definida, você renderiza a resposta do servidor.

🛠 Faça logout e login novamente para obter um novo token de acesso da Auth0 que inclui as informações de audiência.

🛠 Visite http://localhost:4040/external-api e clique em qualquer um dos botões na página da API externa para testar as respostas. Você pode ser solicitado a fazer login, dependendo da ação que escolher executar.

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.

Agora tem um problema... Visite http://localhost:4040/external-api/protected-message. Depois de fazer login, você verá o resultado. Agora tente fazer log out...

Você recebe uma mensagem de erro:

Cannot GET /logout/external-api/protected-message.

Se você tentar fazer login em http://localhost:4040/external-api/public-message, receberá um erro semelhante:

Cannot GET /login/external-api/public-message

Não há um controlador de rota para lidar com as seguintes requisições:

GET /sign-up/:page/:section

GET /login/:page/:section

GET /logout/:page/:section

Você pode criar um controlador de rota para lidar com esses caminhos específicos, mas não há necessidade. Você pode adicionar section como um parâmetro opcional para os controladores de rota de autenticação existentes.

🛠 Abra o arquivo src/index.js e localize a subseção Routes Definitions > Authentication. Atualize esta seção da seguinte forma:

// src/index.js

/**
 * Routes Definitions
 */

// > Authentication

app.get('/sign-up/:page/:section?', (req, res) => {
  const { page, section } = req.params;

  res.oidc.login({
    returnTo: section ? `${page}/${section}` : page,
    authorizationParams: {
      screen_hint: 'signup',
    },
  });
});

app.get('/login/:page/:section?', (req, res) => {
  const { page, section } = req.params;

  res.oidc.login({
    returnTo: section ? `${page}/${section}` : page,
  });
});

app.get('/logout/:page/:section?', (req, res) => {
  const { page } = req.params;

  res.oidc.logout({
    returnTo: page,
  });
});

Vamos testar esse ajuste.

🛠 Visite http://localhost:4040/external-api/protected-message e faça logout. Você deve ser levado para a página “External API”.

🛠 Visite http://localhost:4040/external-api/public-message e faça login daí. Você deveria ter permanecido na mesma página.

Conclusão

Você implementou a autenticação de usuário no Express 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 web Express: inscrição, login e logout simples e chamada de APIs protegidas.

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 uma pop-up em vez de um redirecionamento para fazer login de usuários, adicionar permissões ao namespace oidc, usar metadados para aprimorar perfis de usuário e muito mais.

Deixe-me saber nos comentários abaixo se você gostou deste tutorial. Obrigado por ler este post e fica de olho para mais posts como esse.

  • Twitter icon
  • LinkedIn icon
  • Faceboook icon