developers

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.

Dec 22, 20221 min read

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,

authRequired
e
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.