Implementando Authorization Code Grant (PKCE)
Clase 25 de 39 • Curso de Autenticación con OAuth
Authorization Code Grant tiene algunos problemas de seguridad cuando se implementa en aplicaciones nativas. Por ejemplo, un atacante malicioso puede interceptar el authorization_code retornado por el Authorization Server y usarlo para obtener un Access Token.
La Proof Key for Code Exchange (PKCE), definida en https://tools.ietf.org/html/rfc7636, es una técnica usada para mitigar la intercepción del authorization_code.
Con PKCE la aplicación crea, por cada petición de autorización, una llave criptográfica aleatoria llamada code_verifier y su valor transformado llamado code_challenge el cual es enviado al Authorization Server para obtener un authorization_code y posteriormente enviarlo junto con el code_verifier para obtener un Access Token.
Conociendo el flujo
- La aplicación nativa inicia el flujo y redirecciona al usuario al Authorization Server enviando los parámetros
code_challengeycode_challenge_method. - El Authorization Server redirecciona el usuario a la aplicación nativa con un
authorization_codeen el query string. - La aplicación nativa envía el
authorization_codey elcode_verifierjunto con la url de redireccionamiento (redirect_uri) y elclient_idal Authorization Server. - El Authorization Server valida la información y retorna un Access Token.
- La aplicación nativa ahora puede usar el Access Token para llamar los recursos en nombre del usuario (API).
Detalles de implementación
Vamos a ver los detalles de implementación usando JavaScript/Node.js, ya que son operaciones y request básicos que puede implementar cualquier lenguaje nativo. Para ver más detalles de una implementación especifica en lenguajes como Java o Swift pueden consultar una guía aquí.
- Necesitamos generar y almacenar un
code_verifier.
function base64URLEncode(str) { return str .toString("base64") .replace(/\+/g, "-") .replace(/\//g, "_") .replace(/=/g, ""); } const verifier = base64URLEncode(crypto.randomBytes(32));
- Mediante el
code_verifiergeneramos uncode_challengeque será enviando en el llamado de autorización.
function sha256(buffer) { return crypto .createHash("sha256") .update(buffer) .digest(); } const challenge = base64URLEncode(sha256(verifier));
- Para comenzar el Authorization Code Grant (PKCE), nuestra aplicación nativa deberá enviar primero el usuario a la url de autorización incluyendo el
code_challengey el método usado para su generación y así obtener elauthorization_code.
https://<authorization-server>/authorize? audience=<your-audience>& scope=<your-scopes>& response_type=code& client_id=<your-cient-id>& code_challenge=<code-challenge>& code_challenge_method=S256& redirect_uri=<your-redirect-uri>
- Ahora que nuestra aplicación tiene el
authorization_codelo debemos cambiar por un Access Token que puede ser usado para hacer llamados a los recursos del usuario. Para ello obtenemos elauthorization_code(code) de nuestro paso anterior y hacemos un llamado tipoPOSTal endpoint de obtención de token enviando también elcode_verifier.
const request = require("request"); const options = { method: "POST", url: "https://<authorization-server>/oauth/token", headers: { "content-type": "application/json" }, body: '{"grant_type":"authorization_code","client_id": "<your-client-id>","code_verifier": "<your-code-verifier>","code": "<your-authorization-code>","redirect_uri": "<your-redirect-uri>"}' }; request(options, function(error, response, body) { if (error) throw new Error(error); console.log(body); });
La respuesta tiene un JSON Web Token, generalmente de tipo Bearer:
{ "access_token": "eyJz93a...k4laUWw", "token_type": "Bearer" }
- Ya teniendo nuestro Access Token podemos hacer llamados a los recursos del usuario (API) en nombre de él.
const request = require("request"); const options = { method: "GET", url: "https://someapi.com/api", headers: { authorization: "Bearer <access-token>", "content-type": "application/json" } }; request(options, function(error, response, body) { if (error) throw new Error(error); console.log(body); });
Con esto tenemos los conocimientos necesarios para poder implementar este flujo. Recuerda seguir las recomendaciones para darle un uso adecuado.