Olá pessoal, hoje queria comentar sobre a tecnologia TOTP, usada no Google Authenticator para segundo fator de segurança, e uma maneira de como podemos usar isso nas chamadas de APIs, de forma transparente sem solicitar ao usuário que digite os números gerados manualmente.
O que é e como funciona o TOTP e HOTP
Explicando de uma forma simples e resumida, ambas tecnologias geram tokens que podem mudar de tempo em tempo, e seguindo alguma regras é possível controlar quando mudar.
O HOTP é um algoritmo que irá gerar o secret e o código de 6 dígitos, que é válido até que seu contador seja incrementado! Explico: supondo que fiz a solicitação para o backend, posso incrementar esse contador em 1, toda vez que faço isso a chave de 6 dígitos irá mudar, logo tanto o Front como o backend devem estar pareados para que estejam na mesma versão.
O TOTP segue uma lógica baseada em tempo, exemplo, a cada X segundos tanto o cliente quanto o servidor irão mudar sua chave, tendo o secret original salvo no front, mesmo sem internet ambos irão gerar o mesmo código, ou seja, é assim que funcionavam aqueles tokens chaveiros do Itaú, o Google Authenticator etc.

Deixo no final do artigo um link para uma explicação mais detalhada de suas diferenças.
Porque usar o TOTP
Usar o HOTP vai exigir que controlemos o número de iterações realizadas com ele, podemos usar alguma lógica, tipo, mudar o token a cada 10 chamadas, porém isso é um problema quando temos chamadas assíncronas pela parte do cliente, a gestão dessas chamadas e a garantia de que estamos controlando de forma correta seria muito complicado, dependendo de como implementado, de sua internet e de outros fatores a primeira chamada a API com o código de incremento antigo, pode chegar após uma outra chamada que esta nessa fila e foi atendido primeiro, fazendo que o backend esteja no contador 1 e sua API já chamou passando o 2, ou então, atualizaríamos o contador no backend antes da chamada que foi enviada primeiro chegar, então teríamos esses problemas de fila.
Caso fossemos usar o OAuth 2 temos o “problema” que devemos guardar o token permanente e o temporário, sendo que o permanente pode ser usado para gerar um novo temporário, porém isso aumenta o número de chamadas a APIs, pensando neste cenário. soma-se o fato que, provavelmente, o tempo para expirar será grande, para tentar diminuir essa troca de tokens.
Utilizando o TOTP teremos um token novo a cada 1 minuto, sendo que o front consegue calcular o próximo token em tempo real!. Configurando corretamente temos 30 segundos de validade até o cálculo do próximo token, porém ainda deixamos o token anterior ativo por mais 30 segundos, para não correr o risco de no tempo de resposta da API o token ter expirado (claro que sua API teria que responder em menos de 30 segundos para garantir, o que convenhamos é muito tempo.) Caso sua API seja uma carroça… digo muito lenta é possível aumentar esse tempo.
Observação, essa ideia pode ser usada para ser uma alternativa ao OAuth 2, ou um incremento, dependendo de como for implementar. Mas não considero mais seguro que ele tão pouco mais seguro do que usar um Google Authenticator, que na realidade ele é mais seguro ainda, porque o secret token ficaria num terceiro aplicativo, porém tem o inconveniente de solicitar ao usuário digitar, o que inviabiliza utilizar em todas chamadas de APIs que é a minha proposta.
Como fica na teoria?
Vão existir várias possibilidades de implementação, vou seguir numa linha de raciocínio, mas você deve tentar adaptar a suas necessidades, no meu caso quando o login for realizado vou enviar uma flag solicitando um secret, seja o primeiro ou para gerar um novo e associá-lo ao usuário. O backend irá me devolver o secret e no frontend vou armazená-lo, sendo que só vou apagá-lo quando o usuário fizer um logoff ou desinstalar o aplicativo (no meu caso meu front são aplicações móveis.)
Em todas requisições vou enviar no header o código de 6 dígitos gerados a partir do secret, porém preciso ainda enviar alguma identificação do usuário, no meu caso tenho um token de usuário também, que recebi no login. Então no meu header envio o código gerado + o bearer token do usuário.

Como gerar de forma prática o secret e o código de 6 dígitos?
Vou exemplificar com Nodejs, abaixo deixo link para o Github do projeto completo, com HOTP e TOTP, também com um exemplo no Postman.
/*
Configuração básica do projeto
*/
const express = require("express");
const body = require("body-parser");
const speakeasy = require("speakeasy"); //Lib que faz a mágica
var app = express()
.use(body.json())
.use(body.urlencoded({extended: true}));
/*
Rota para solicitar o secret
*/
app.post("/otp-secret", (request,response, next) => {
var secret = speakeasy.generateSecret({ length: 20 });
response.send({ "secret": secret.base32 });
});
/*
Validar o código recebido
*/
app.post("/totp-validate", (request,response, next) => {
response.send(
{
"valid": speakeasy.totp.verify({
"secret": request.body.secret, //Não passar assim, pegar da base de dados.
"encoding": "base32",
"token": request.body.token, //Token de 6 números.
"window": 1 //tempo após expirar o código anterior, 1 = ON + 30 segundos, 0 = OFF
}),
"request": { //Only test
"secret": request.body.secret,
"token": request.body.token
},
"remaining": (30 - Math.floor((new Date().getTime() / 1000.0 % 30))) //tempo de validade
}
);
});
/*
Aqui quem deve fazer é seu frontend, mas é um exemplo de como gerar o código de 6 dígitos nessa lib
*/
app.post("/totp-code", (request,response, next) => {
response.send(
{
"token": speakeasy.totp({
"secret": request.body.secret,
"encoding": "base32"
}),
"request": { //Only test
"secret": request.body.secret
},
"remaining": (30 - Math.floor((new Date().getTime() / 1000.0 % 30))) //tempo de validade
}
);
});
Conclusão
Como apontei até aqui, esse é um modo de aplicar o TOTP, uma aplicação similar são pagamentos em apps bancários, quando ele mesmo informa que vai consultar seu iToken, e sem perguntar ao usuário, validam a transação, porém no nosso caso iremos usar como um fator de segurança adicional nas chamadas das APIs. Assim se algum hacker interceptar uma chamada do seu front para a API, será mais complicado, pois depois de segundos a chave já será inválida.
E lembrando que sempre é valido usar mais fatores de segurança, como enviar a chave de 6 dígitos criptografada, por exemplo.

Testes automatizados no postman, validando os tokens gerados.
Projeto no Github
Lib que usei no projeto em NODE: Speakeasy
Tutorial completo para implementar em NODE: https://www.youtube.com/watch?v=Yv5tZu5wAU0
Artigo completo sobre as diferenças de OTP, TOTP e HOTP