Português (Brasil)
  • oidc
  • oauth
  • authentication
  • authorization
  • jwt

O guia completo para integrar um servidor OIDC no seu projeto

Aprenda as melhores práticas de integração de um servidor OIDC (OpenID Connect) no seu projeto e entenda como os componentes interagem entre si no estágio.

Gao
Gao
Founder

Você pode se deparar com uma situação onde precisa de um sistema centralizado de autenticação e autorização, também conhecido como gerenciamento de acesso de identidade (IAM) ou provedor de identidade (IdP). Às vezes as pessoas acrescentam uma palavra para designar o negócio, como Cliente IAM e Equipe IAM.

Vamos deixar esses nomes sofisticados de lado por um momento. A necessidade de um IAM pode surgir porque sua aplicação está crescendo, ou você planeja delegar o trabalho duro a um fornecedor desde o início. No entanto, você está chegando a um ponto onde um sistema de identidade precisará ser introduzido no seu projeto.

Considerando a popularidade do OAuth 2.0, o OpenID Connect (OIDC) é uma escolha natural para muitos desenvolvedores. Como o OIDC é uma camada de autenticação construída sobre o OAuth 2.0, você pode achar familiar quando começar a trabalhar com o OIDC. Vamos começar!

O que é um servidor OIDC e por que devo integrar o servidor OIDC?

Um servidor OIDC, ou provedor de identidade, é um sistema centralizado que gerencia a autenticação e autorização dos usuários. Como discutimos em Por que você precisa de um sistema de identidade centralizado para um negócio multiaplicativo, um sistema de identidade centralizado tem muitos benefícios.

Digamos que seu projeto comece com uma aplicação web simples, e ela tenha autenticação embutida:

À medida que seu projeto cresce, você precisa introduzir uma versão móvel:

Será uma má experiência para os usuários se eles precisarem criar uma conta para cada aplicação. Como você começou com uma aplicação web, deixou a aplicação móvel se comunicar com a aplicação web para autenticação:

Agora, um novo serviço de API está sendo introduzido. Como é um serviço para usuários pagos, você precisa garantir que o usuário esteja autenticado e autorizado a acessar o serviço. Para alcançar isso, você pode usar um proxy através da aplicação web:

Ou, usar alguma técnica de token para autenticar o usuário e validar o token conversando com a aplicação web no serviço. Portanto, a aplicação móvel pode usar o serviço diretamente:

As coisas estão ficando confusas. Então, você decide dividir a lógica de autenticação e autorização em um serviço separado:

O processo de refatoração pode ser doloroso. Você pode notar que a complexidade aumentará exponencialmente à medida que adicionar mais aplicações e serviços ao projeto. Ainda pior, você pode precisar manter múltiplos métodos de autenticação, como login sem senha, login social, SAML etc.

É por isso que é melhor introduzir um provedor de identidade no início, quando você tem um plano para escalar seu projeto.

Melhores práticas para integrar um servidor OIDC

Encontre um provedor OIDC

Há muitos provedores OIDC disponíveis no mercado. Você pode escolher um com base em seus requisitos e preferências. Desde que o provedor seja compatível com OIDC, ele desempenhará o mesmo papel no seu projeto.

O que significam “sujeito”, “cliente” e “audiência” no OIDC?

Para simplificar o conceito, podemos pensar que o sujeito é a entidade que está solicitando acesso a uma audiência através de um cliente.

Vamos ver alguns cenários típicos:

1. Um usuário clica no botão de login em uma aplicação web

Em uma aplicação web tradicional e de renderização no lado do servidor, o frontend e o backend estão acoplados. Digamos que a aplicação web sirva tanto o frontend quanto o backend:

  • Sujeito: O usuário
  • Audiência: O servidor OIDC
  • Cliente: A aplicação web

Pode parecer contra-intuitivo que a audiência seja o servidor OIDC. Na verdade, é a chave para realizar a experiência SSO (Single Sign-On) para os usuários finais. Vamos ver um diagrama de sequência simplificado para fluxo de código de autorização:

código é um código único que pode ser trocado por vários tokens, como token de acesso, ID token e token de atualização. Está tudo bem se você não entender todos esses tokens neste momento. À medida que avançarmos, você terá uma melhor compreensão deles.

No caso acima, o usuário não precisa fazer login novamente quando troca para outra aplicação porque o usuário (sujeito) já foi autenticado com o servidor OIDC (audiência).

2. Um usuário usa uma aplicação de página única

Em uma aplicação de página única (ou uma aplicação móvel), o frontend e o backend são separados. Digamos que o backend é um serviço de API:

  • Sujeito: O usuário
  • Audiência: O serviço de API
  • Cliente: A aplicação de página única (SPA)

Um diagrama de sequência simplificado com fluxo de código de autorização:

Como o serviço de API é não-interativo, a SPA precisa usar o token de acesso com o serviço de API como a audiência (o aud no token).

Por que o servidor OIDC ainda é uma audiência?

Tecnicamente, você pode remover o servidor OIDC da lista de audiências. Como na maioria dos casos, você precisará das informações do usuário do servidor OIDC (o que requer que o servidor OIDC seja a audiência), é melhor sempre incluir o servidor OIDC na lista de audiências quando envolve interação do usuário.

Espere, você está dizendo que podemos ter múltiplas audiências em uma solicitação de autorização?

Exatamente! Lembre-se que o OIDC é construído sobre o OAuth 2.0, é possível alavancar RFC 8707: Indicadores de Recurso para OAuth 2.0 na solicitação de autorização para especificar múltiplas audiências. Isso requer suporte tanto da concessão quanto do servidor OIDC. Logto suporta esse recurso nativamente.

3. Comunicação de máquina para máquina

Digamos que você tenha um serviço A que precisa chamar o serviço B:

  • Sujeito: Serviço A
  • Audiência: Serviço B
  • Cliente: Serviço A

Um diagrama de sequência simplificado com concessão de credenciais do cliente:

Quando o serviço B precisa chamar o serviço A, os papéis são simplesmente trocados.

Recapitulação

  • Sujeito: Pode ser um usuário, um serviço ou qualquer entidade que precisa acessar a audiência.
  • Cliente: Pode ser uma aplicação web, uma aplicação móvel, ou qualquer entidade que inicia a solicitação ou age em nome do sujeito.
  • Audiência: Pode ser um serviço, uma API ou qualquer entidade que fornece acesso ao sujeito.

O que são tokens de acesso, ID tokens e tokens de atualização?

Há três tipos de tokens que você pode encontrar ao trabalhar com OIDC:

  • Token de acesso: É usado para acessar a audiência. Pode ser um JWT (JSON Web Token) ou um token opaco (geralmente uma string aleatória).
  • ID token: Um token específico do OIDC que contém informações do usuário. É sempre um JWT. O cliente pode decodificar o token para obter informações do usuário.
  • Token de atualização: É usado para obter um novo conjunto de tokens quando o token de acesso ou ID token expira.

Para uma explicação detalhada desses tokens, você pode consultar Entendendo tokens de atualização, tokens de acesso e ID tokens no protocolo OIDC.

Nos cenários 1 e 2 acima, o termo solicitação de autorização refere-se a uma solicitação para obter um conjunto de tokens através de uma concessão específica.

Quando tudo corre bem, um conjunto de tokens será retornado na etapa "Troca tokens usando código". Os tokens disponíveis no conjunto dependem de vários fatores, especialmente do parâmetro scope na solicitação de autorização. Para simplificar, assumiremos que todos os tokens são retornados no conjunto. Uma vez que o token de acesso expira, o cliente pode usar o token de atualização para obter um novo conjunto de tokens sem interação do usuário.

Para o cenário 3, é mais simples porque a concessão de credenciais do cliente só retorna um token de acesso.

Como lidar com múltiplas audiências no OIDC?

Você pode notar que apenas um token de acesso é retornado por vez. Como poderíamos lidar com o caso em que o cliente precisa acessar múltiplas audiências?

Há duas soluções comuns:

Especificar resource na solicitação de troca de código

Quando o cliente troca o código por tokens, pode especificar um parâmetro resource na solicitação. O servidor OIDC retornará um token de acesso para a audiência especificada, se aplicável.

Aqui está um exemplo não normativo:

Então, o servidor OIDC retornará um token de acesso para a audiência API_SERVICE, se aplicável.

Usar um token de atualização para obter um novo token de acesso

Com o RFC 8707, o cliente pode até especificar múltiplas audiências usando o parâmetro resource várias vezes. Agora, se o token de atualização estiver disponível no cliente, o cliente pode especificar a audiência no parâmetro resource ao atualizar o token.

Aqui está um exemplo não normativo:

Isso tem o mesmo efeito que a solução anterior. Enquanto isso, outras audiências concedidas ainda estão disponíveis em futuras solicitações de token.

Concessão de credenciais do cliente

Você também pode usar o parâmetro resource na concessão de credenciais do cliente para especificar a audiência. Não há problema com múltiplas audiências nessa concessão, pois você pode sempre solicitar um novo token de acesso para uma audiência diferente, simplesmente enviando outra solicitação de token.

Proteja seu serviço de API

O "serviço de API" no cenário 2 e o "Serviço B" no cenário 3 têm uma coisa em comum: eles precisam validar o token de acesso para determinar se a solicitação é autorizada. Dependendo do formato do token de acesso, o processo de validação pode variar.

  • Token opaco: O serviço de API precisa chamar o servidor OIDC para validar o token. Um endpoint de introspecção é geralmente fornecido pelo servidor OIDC para esse propósito.
  • JWT: O serviço de API pode validar o token localmente verificando a assinatura e as declarações no token. O servidor OIDC geralmente fornece um JSON Web Key Set (JWKS) endpoint (jwks_uri) para o serviço de API obter a chave pública para verificar a assinatura.

Se você é novo no JWT, pode consultar O que é JSON Web Token (JWT)?. Na verdade, geralmente não há necessidade de validar a assinatura e verificar as declarações manualmente, pois existem muitas bibliotecas que podem fazer isso por você, como jose para Node.js e navegadores web.

Verifique as declarações

Além de validar a assinatura do JWT, o serviço de API deve sempre verificar as declarações no token:

  • iss: O emissor do token. Deve corresponder ao URL do emissor do servidor OIDC.
  • aud: A audiência do token. Deve corresponder ao valor da audiência do serviço de API (geralmente um URI válido).
  • exp: O tempo de expiração do token. O serviço de API deve rejeitar o token se estiver expirado.
  • scope: Os escopos (permissões) do token. O serviço de API deve verificar se o escopo requerido está presente no token.

Outras declarações, como sub (sujeito) e iat (emitido em), também são importantes em alguns casos. Se você tiver medidas de segurança adicionais, verifique as declarações adequadamente.

Autorização

Resta uma pergunta não respondida: como determinamos se um escopo (ou seja, permissão) pode ser concedido a um sujeito?

A única pergunta leva a um mundo totalmente novo de autorização, que está fora do escopo deste artigo. Em resumo, há algumas abordagens comuns, como RBAC (Controle de Acesso Baseado em Papéis) e ABAC (Controle de Acesso Baseado em Atributos). Aqui estão alguns recursos para você começar:

Notas finais

Introduzir um servidor OIDC no seu projeto é um grande passo. Pode melhorar significativamente a segurança e a escalabilidade do seu projeto. Enquanto isso, pode levar algum tempo para entender os conceitos e as interações entre os componentes.

Escolher um bom provedor OIDC que atenda aos seus requisitos e preferências pode reduzir notavelmente a complexidade do processo de integração, pois o provedor geralmente oferece o pacote completo, incluindo o servidor OIDC, mecanismos de autorização, SDKs e os recursos empresariais que você possa precisar no futuro.

Espero que este guia ajude você a entender o básico da integração de um servidor OIDC. Se você está procurando um para começar, eu recomendaria sem rodeios o Logto, nossa infraestrutura de identidade para desenvolvedores.