Docs
...

Step-up: exigindo uma autenticação mais forte

Nem toda ação dentro de uma aplicação tem o mesmo peso. Consultar um extrato e solicitar uma transferência exigem níveis de confiança diferentes, mesmo que sejam feitos pelo mesmo usuário, na mesma sessão.

O step-up é o mecanismo que permite à sua aplicação dizer ao Identity: “para esta ação específica, eu preciso de uma autenticação mais forte do que a que este usuário fez”. O Identity apresenta o desafio adequado ao usuário e devolve um token que carrega, de forma verificável, o nível de autenticação alcançado.

Ele é a implementação do OAuth 2.0 Step Up Authentication Challenge Protocol e usa dois conceitos do OpenID Connect:

  • acr (authentication context class reference) — o nível de autenticação alcançado.
  • auth_time — o momento (unix timestamp em UTC) da última autenticação do usuário.

Primeira vez integrando? Comece pela visão geral da integração OAuth e pelo passo a passo do Authorization Code. O step-up é um acréscimo a esse fluxo, não um fluxo novo.

Níveis disponíveis

Valor de acr_values Quando usar Validade da autenticação
urn:iugu:grant_scopes:informations Nível padrão. Aplicado quando sua aplicação não pede nenhum nível específico. Longa
urn:iugu:grant_scopes:config Ações sensíveis de configuração — gerar credenciais, convidar membros, alterar dados cadastrais. Curta (minutos)
urn:iugu:grant_scopes:transfers Ações críticas, especialmente as que movimentam dinheiro. Muito curta (cerca de um minuto)

Os níveis são ordenados: transfers é mais forte que config, que é mais forte que informations. O Identity decide qual desafio apresentar ao usuário de acordo com o nível pedido e com o que o usuário já fez na sessão atual — sua aplicação não escolhe nem precisa conhecer o desafio.

Warning

Não fixe os tempos de validade no código da sua aplicação. Eles podem ser ajustados pela iugu. Use sempre as claims acr e auth_time do token para decidir se a autenticação ainda vale.

A lista de níveis também é publicada no campo acr_values_supported do documento de descoberta do Identity, em https://id.iugu.com/.well-known/openid-configuration, ordenada do mais fraco para o mais forte.

Pré-requisito

Para receber tokens de nível elevado, a sua aplicação precisa ter o grant scope correspondente habilitado na aba Credenciais do painel de administração do seu aplicativo.

Como funciona

sequenceDiagram autonumber participant U as Browser do Usuário participant A as Sua Aplicação participant I as Identity U ->> A: Solicita uma ação sensível A ->> A: Verifica as claims acr e auth_time do token atual A ->> U: Redireciona para /authorize informando acr_values U ->> I: Envia o request de autenticação I ->> U: Apresenta o desafio adequado ao nível pedido U ->> A: É redirecionado para a URI de callback com o code A ->> I: Troca o code pelos tokens I ->> A: Emite os tokens já com o acr elevado e um novo auth_time A ->> A: Revalida acr e auth_time e executa a ação
  1. O usuário pede uma ação que a sua aplicação classificou como sensível.
  2. Sua aplicação verifica se o token atual já tem o nível necessário e se ele ainda está dentro da janela de validade que ela exige.
  3. Se não tiver, sua aplicação redireciona o usuário para o /authorize, informando o nível desejado no parâmetro acr_values.
  4. O Identity apresenta o desafio ao usuário. Se ele já satisfaz o nível pedido, nenhum desafio é apresentado e o fluxo segue direto.
  5. Concluído o desafio, o fluxo do authorization code segue normalmente e os tokens emitidos trazem o novo acr e um auth_time atualizado.
  6. Sua aplicação valida os tokens e executa a ação.
  7. Passada a janela de validade, o usuário volta ao nível padrão. Uma nova ação sensível exige um novo step-up.

Passo a passo de implementação

1 - Verificar o nível do token atual

Antes de executar a ação sensível, compare o acr do token com o nível exigido e confira há quanto tempo o usuário se autenticou, usando o auth_time.

NIVEL_EXIGIDO = "urn:iugu:grant_scopes:config"
JANELA        = 5.minutes

def nivel_suficiente?(token)
  token["acr"] == NIVEL_EXIGIDO &&
    Time.now.to_i - token["auth_time"] < JANELA.to_i
end

Warning

Verificar apenas a claim exp não é suficiente. O exp diz se o token expirou; o auth_time diz há quanto tempo o usuário se autenticou. Um token pode estar válido e, ainda assim, a autenticação que o originou já ser antiga demais para uma ação crítica.

2 - Redirecionar o usuário para o /authorize com o nível desejado

O request é o mesmo do authorization code, com dois parâmetros opcionais a mais.

Parâmetros do step-up

  • acr_values — o nível de autenticação exigido. Sempre gere um novo state para este novo request, como em qualquer chamada ao /authorize.
  • max_age — opcional. Tempo máximo, em segundos, que sua aplicação aceita ter se passado desde a última autenticação do usuário.
https://id.iugu.com/authorize?
    response_type=code&
    client_id=2pWTsl4ZyO59S1Ft5eXTwV&
    redirect_uri=https%3A//oauth2.example.com/code&
    state=a4EUklMAM8gqu7PkzwR4NwCu5yXYrls9Uhr/rnWnI7/LEor3jyRKLp5D/1PjSB1I4MdgqmzD2tzgpB0Xb0Bf2A==&
    acr_values=urn%3Aiugu%3Agrant_scopes%3Aconfig

Enviando mais de um nível. O parâmetro aceita vários valores separados por espaço (%20 na URL). Quando isso acontece, o Identity aplica o nível mais forte entre os valores reconhecidos:

acr_values=urn%3Aiugu%3Agrant_scopes%3Aconfig%20urn%3Aiugu%3Agrant_scopes%3Atransfers
# resultado: urn:iugu:grant_scopes:transfers

Sobre o max_age. Ele só pode restringir a janela padrão do nível, nunca ampliá-la. Se o max_age enviado for maior que a validade do nível, vale a validade do nível.

3 - Receber o callback e trocar o code pelos tokens

Nada muda em relação ao fluxo padrão: confirme o state e faça o POST para o /token, exatamente como descrito nos passos 3 e 4 do authorization code.

4 - Validar o nível recebido

Depois de validar a assinatura dos tokens, confirme o nível antes de executar a ação. Um token elevado tem esta aparência:

{
  "iss": "https://id.iugu.com",
  "sub": "user:75zmir54C2vbpQrz5E0uFA",
  "aud": ["4BW4pFc06UmLyuUG83F0GH"],
  "client_id": "4BW4pFc06UmLyuUG83F0GH",
  "acr": "urn:iugu:grant_scopes:config",
  "auth_time": 1726869662,
  "iat": 1726869667,
  "exp": 1726869727
}

Warning

Sempre trate o acr recebido como um dado a ser verificado. Pedir um nível no acr_values não garante que ele foi alcançado — quem decide é o Identity, e a resposta está na claim acr.

5 - Executar a ação e voltar ao nível padrão

Execute a ação sensível imediatamente. Quando a janela expira, o usuário volta ao nível padrão e um novo step-up será necessário na próxima ação sensível.

Warning

Tokens de nível elevado não vêm acompanhados de refresh_token. Eles são propositalmente curtos e não renováveis sem a presença do usuário: tentar renovar um token elevado pelo /token com grant_type=refresh_token retorna invalid_grant. Para voltar ao nível elevado, refaça o step-up.

Erros

Os erros do /authorize são devolvidos na query string da sua redirect_uri quando ela e o client_id são válidos; caso contrário, vêm como JSON com status HTTP 400. Trate os dois formatos.

error Quando acontece O que fazer
invalid_request Nenhum dos valores enviados em acr_values é um nível reconhecido, ou o max_age não é um inteiro não negativo. Corrija os parâmetros; é um erro de integração.
unmet_authentication_requirements O usuário concluiu um desafio que não satisfaz o nível pedido. Não execute a ação. Ofereça ao usuário a opção de tentar novamente.
{
  "error": "unmet_authentication_requirements",
  "error_description": "The authentication method used does not satisfy the requirements for the requested ACR value",
  "state": "a4EUklMAM8gqu7PkzwR4NwCu5yXYrls9Uhr..."
}

Boas práticas

  • Classifique as ações da sua aplicação por nível uma única vez, em um ponto central, em vez de espalhar a decisão por cada rota.
  • Revalide acr e auth_time no momento de executar a ação, não apenas no momento em que a tela foi carregada.
  • Guarde o destino do usuário antes de redirecioná-lo ao /authorize, para levá-lo de volta à ação que ele havia pedido.
  • Nunca conceda a ação sensível com base apenas na intenção do redirect. A prova é sempre a claim acr de um token com assinatura validada.

Para aprofundar