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
- O usuário pede uma ação que a sua aplicação classificou como sensível.
- 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.
- Se não tiver, sua aplicação redireciona o usuário para o
/authorize, informando o nível desejado no parâmetroacr_values. - O Identity apresenta o desafio ao usuário. Se ele já satisfaz o nível pedido, nenhum desafio é apresentado e o fluxo segue direto.
- Concluído o desafio, o fluxo do authorization code segue normalmente e os tokens emitidos
trazem o novo
acre umauth_timeatualizado. - Sua aplicação valida os tokens e executa a ação.
- 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 novostatepara 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
acreauth_timeno 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
acrde um token com assinatura validada.