logo

midudev


Transcribed podcasts: 146
Time transcribed: 5d 9h 42m 56s

This graph shows how many times the word ______ has been mentioned throughout the history of the program.

En la clase de hoy vamos a ver JavaScript Web Tokens y vamos a conseguir que nuestro usuario tenga sesión.
Vamos a querer que sólo los usuarios que están autenticados puedan realmente crear una nota.
Y para eso, en la clase anterior vimos cómo podíamos registrar usuarios, pues en esta vamos a ver cómo pueden iniciar sesión
y además vamos a ver cómo podemos mantener esa sesión, cómo guardarla, cuál es la buena práctica para hacer esto.
Y luego vamos a tener que volver al frontend y esto nos abrirá una de clases por delante,
porque volveremos al frontend, tendremos la sesión del usuario y a partir de aquí vamos a ir viendo qué hacemos de más en el frontend.
Y os digo yo que nos queda una de las cosas más interesantes.
Nos vamos aquí al código, esta sería la clase de hoy, la autenticación con token.
Así que vamos con la autenticación con token.
Vamos a ver este diagrama, que es lo que básicamente vamos a conseguir en la clase de hoy.
Lo que queremos es que el usuario va a ir a un formulario para iniciar su sesión, va a poner su usuario y su password
y esto le dará al botoncito, clic, el botoncito del navegador hará una petición post a api barra login con el usuario y el password
y nuestro backend, que es lo que vamos a hacer ahora, nos va a generar un token para identificar a este usuario.
Ahora, lo que va a hacer este token es devolvérselo al navegador y aquí lo guardaremos.
Hay diferentes formas de guardarlo, yo os explicaré unas cuantas, nosotros vamos a hacer una en concreto,
pero os explicaré algunas cosas que se pueden hacer, que no se deben hacer, buenas prácticas,
gente que dice que no son buenas prácticas, un poco de todo para que tengáis un poco de contexto.
De esta forma, una vez que tenemos el token, aquí, este token que lo guardaremos en el cliente,
el usuario cuando cree una nota, pues utilizaremos este token, lo enviaremos en el header,
de forma que el backend pueda identificar a este usuario y pueda crear la nota.
Que tenga permisos, básicamente, de crear la nota.
Esto, este diagrama, es lo que vamos a hacer en la clase de hoy.
Básicamente, este diagrama es lo que hacemos en la clase de hoy.
Pues vamos a ir ya a nuestra clase, vamos a quitar esto.
Este es el repositorio donde tenemos el código por si quieres seguir la clase o las anteriores clases.
Aquí tenemos todas las clases, las tenemos aquí.
Y aquí puedes ver el código que tenemos en master, es el último disponible.
Pero si quieres volver una para atrás, pues nada, seleccionar la clase y ahí tendrías el código disponible.
Yo voy a tirar de lo que tengo de master ahora mismo.
Así que lo primero que vamos a hacer, como he dicho, es que tenemos que iniciar sesión con el usuario.
Y he dicho que lo vamos a hacer con JavaScript Web Tokens, lo iremos viendo.
Lo importante es que necesitamos una ruta para nuestro usuario.
Nuestro inicio de sesión tiene que estar en algún sitio.
Como ya teníamos controladores para estas rutas, pues nada, ya le vamos a dar aquí un nuevo controlador.
Vamos a hacer notes, tenemos notes, tenemos users, vamos a hacer login.
Bien, como hicimos en users, si recuerdas un poco que hacíamos esto, ¿no?
User router, no sé qué.
Pues vamos a hacer algo muy similar.
Así que vamos a poner aquí, vamos a necesitar bcrip, que en una clase anterior lo vimos lo que era,
para qué servía y tal, que era para hacer el hash del password.
Y aquí lo que tenemos que hacer es crear el router, ¿no?
Pues login router.
Esto también lo hemos visto en la clase anterior.
Pero bueno, hay que hacerlo, hay que hacerlo, hay que hacerlo.
El login router.
Y ahora vamos a traernos, porque también lo vamos a necesitar, el modelo del usuario.
Así que vamos a models y nos traemos el modelo del usuario.
Ahora en login router vamos a tener un post, como hemos visto antes en la imagen.
Y aquí lo vamos a poner, que es en el path, que es la raíz, con el slash.
Y aquí, pues nada, ya tenemos el callback con la request y la response.
Y ahora, con este método async, vamos a empezar aquí.
Primero, a recuperar el body de la request, porque le tenemos que pasar tanto el usuario como el password.
Y ahora que tenemos esa información, lo primero que podemos hacer es buscar justamente ese usuario en nuestra base de datos.
Vamos a ver si existe, ¿no?
Con el username, que el username lo vamos a recuperar del body, ¿vale?
En el body vamos a tener tanto username como password.
Aquí tendríamos, si lo ha encontrado, que ahora veremos, ¿no?
Que puede ser interesante que no lo encuentre y alguien intente, pues, ver si está o no está.
Pero, en principio, intentamos recuperar el usuario, ¿vale?
Y ahora que tenemos esto, podríamos mirar si el password es correcto o no es correcto.
Lo primero que podemos hacer, hombre, si el usuario es igual a nul, o sea, que no lo ha encontrado, pues, ya decimos que el password no es correcto.
Y ahora te explico un poco esto, cómo podríamos hacerlo de una forma distinta, pero creo que es mejor que lo hagamos así.
Si no, si el usuario sí que lo ha encontrado, lo que vamos a intentar es, del body, que es lo que le estamos enviando a la ruta, vamos a recuperar también el password.
Y si recuerdas de clases anteriores, lo que hacíamos, básicamente, es que el password en el cliente, claro, no está hasheado, pero nosotros en las rutas lo tenemos que hashear, porque la base de datos sí que lo guardamos, pues, con seguridad.
Así que aquí tenemos que hacer un bcrip, punto.
Aquí podríamos crear el hash, como lo hicimos, ¿no?
Pero, en lugar de usar eso, aquí puedes ver que hay un método que se llama compare, que ya te permite comparar directamente dos hashes.
Así no tienes que convertirlo y compararlo y tal.
Vamos a comparar el password y luego lo que vamos a comparar, el segundo parámetro, sería el password hash, que es lo que tenemos en la base de datos que estábamos hasheando y tal, que esto quedaría así.
Y esto nos debería decir si el password es correcto o no es correcto.
Así que si el password es correcto, por ejemplo, si el password no es correcto, podríamos decir, si no es correcto, lo que le podemos poner aquí es un status, creo que es un 401, response.status 401 o 409.
Ah, no me acuerdo si es 401 o 409, el de no autorizado.
Vamos a poner un 401 por ahora.
Y en el JSON podemos poner error, invalid user or password.
Y esto es lo interesante de por qué lo separamos, ¿vale?
Para no darle pistas a alguien que quiera intentar hacer algún tipo de ataque.
¿Por qué?
Porque si nosotros ya le damos aquí la información, por ejemplo, que esto no sé cuántas veces lo habré visto.
Imaginad que aquí ponemos si no tenemos el usuario.
Pues entonces al menos ya le estamos diciendo que, oye, no, es que el usuario no existe.
Ah, bueno, vale, pues me voy a poner a probar hasta que encuentre el usuario.
Ya le estamos dando demasiada información, le estaríamos diciendo, ah, no, es que no hay un usuario con ese nombre.
Ah, vale, pues gracias.
Voy a intentar usuarios todo el rato hasta que encuentre uno y me enfocaré en ese.
Entonces, en lugar de hacer eso, si hacemos esto, lo que hacemos es de, bueno, no solo miro el usuario, sino el password.
Y entonces no te doy información si es el usuario o el password lo que has puesto mal.
Así que las combinaciones son bastante más grandes.
Una vez que si el password sí que es correcto, bueno, ¿qué podríamos hacer aquí?
Pues decir un response.status 200, que esto se supone que es por defecto.
O sea, si yo pongo ya un .en, ya debería, si hacemos .send y ya enviamos aquí, por ejemplo, vamos a enviar del usuario,
podríamos enviar el nombre.
Así que vamos a hacer user.name.
Y podríamos enviar el username también.
User, username.
Esto por aquí.
Con esto debería ser suficiente por ahora.
Vamos a probar si esto funciona.
Vamos a añadir también en las requests, que siempre teníamos que tener aquí las requests, ¿no?
Teníamos, por ejemplo, para crear un usuario teníamos esto.
Y, vale, además, mira, genial que creé este usuario.
Vamos a intentar crearlo.
Se supone que debería apetar porque ya existe este usuario.
La conexión...
Ah, vale.
Apetado porque no tenemos levantado el servicio, ¿vale?
Así que lo vamos a levantar aquí.
En pin run...
No, start es...
Es dev, es dev.
Start es el de producción.
Vamos a poner el modo desarrollo, ¿vale?
Y ahora intentamos enviar la request.
Y nos dice, pues, que no existe...
O sea, que no podemos porque este usuario ya existe.
Lo interesante es que ya tenemos aquí el password que le hemos puesto a este usuario.
Y esto nos va a ayudar a hacer justamente el de login, ¿no?
Vamos a hacer login user.rest.
Y luego lo iremos cambiando porque necesitaremos otras cosas.
Vale.
Antes de...
Antes de utilizarlo, una cosa.
Este router que hemos puesto aquí tendremos que ponerlo en algún sitio.
Esto no funciona así de magia.
Si no, que tenemos que ir al index.js.
E igual que hacíamos el user router que le decíamos el path, esto lo vamos a hacer con el de login.
Así que api barra login.
Vamos a poner login router.
Y esto lo vamos a importar del archivo que acabamos de crear.
Recordad que os dejé como deberes que tenéis que sacar las rutas de las notas.
Yo no lo he hecho porque total, ya me lo sé de memoria.
Pero todas estas rutas de notas tendrías que sacarlo en un controlador.
Nosotros ahora el de usuarios y el de login lo hemos sacado.
Bueno, pues el de login ya estaría.
Vale.
A ver que hay algo que no le ha gustado.
Login router.
Vale.
Lo que no le ha gustado es que no estoy exportando mi controlador.
Vale.
Importante también.
Como que no está conectándose al...
A ver, a ver.
Tenemos el login router.
Tenemos el post.
Tenemos el user.
El user...
Aquí esto está bien en principio.
It's not a function.
Pues esto estaba funcionando hace un momento, ¿no?
Esto básicamente lo tenemos aquí.
Bueno, que a ver.
Esto, claro, esto lo había puesto para cerrar las conexiones.
O sea que esto es que me está dando otro error de alguna cosa.
Y como no estoy poniendo un console error de esto, esto es que teníamos aquí en el proceso
que si encontraba una excepción que intentase cerrar la conexión.
Pero claro, a lo mejor la conexión ni siquiera está.
O sea que este error que me está dando que es tan crítico en realidad es porque me dice
que esto no es una función.
No es así como se hace.
OnGoose.disconnect.
Es así.
Ahora entiendo el error.
Ahora entiendo el error.
Ahora vamos a ver mejor el error, ¿vale?
No puede sobreescribir usuario una vez que ha sido compilado.
Ostras.
En el user, los models, data, user, models, user.js.
Ah, es que este, este user, models, es que este es súper raro porque lo estoy haciendo en minúscula.
Este modelo.
¿No?
Este.
Súper raro.
A ver, lo único que se me ocurre es que crea que este, este archivo lo esté ejecutando dos veces.
Mira, está aquí, ¿ves?
Esto.
Este es el error.
Este es el error.
Es súper raro.
El problema que está pasando aquí es como que me está importando el mismo archivo dos veces.
Esto está mal.
Aquí hay algo raro porque en realidad no, no podría, no, no, no debería poder, no debería poder hacer esto.
Este console.log que estamos viendo aquí solo debería estar una vez.
Entonces, al menos ya hemos encontrado el problema que es lo que te comentaba, ¿no?
Que es de, es como que parece que este modelo lo está recuperando dos veces y ejecutando dos veces.
Este console.log solo lo podríamos ver una vez.
El hecho de que salga dos veces es bastante raro.
Porque esto significa que realmente no está cacheando como tal la llamada del require.
Cuando importas un módulo, aunque sea como en GS, esto tiene una cache que al final esto se debería quedar en memoria totalmente.
En cambio aquí es como que lo está importando dos veces.
Entonces aquí es donde está el problema.
Es donde está el problema.
Cuando hacemos este require aquí no le está gustando porque este está tirando de uno.
De hecho, vamos a quitar un momento esto.
Vamos a poner aquí esto y vamos a poner por aquí, por ejemplo, que el user es un objeto vacío.
Igualmente sale dos veces.
Bueno, pues vamos a ver quién está importando esto.
Compilando, no sé qué.
No, no, no.
Que no, el require en el índice.
Igual es que en algún momento, sin querer, me ha traído algún import que yo me estoy perdiendo.
Pero es lo que ha hecho.
El user router dice, mira, ¿qué se puede ver?
El require, ta, ta, ta.
Aquí.
Dice users en la línea 3.
Este es uno.
Ah, fíjate.
Que esto es user y aquí es...
Ah, no.
No, no.
Y esto es user.
¿Vale?
No me extrañaría que al final tenga que ver realmente con el tema del lowercase.
Porque aquí está en mayúscula y aquí está en lowercase.
No vaya a ser que a la hora de encontrarlos los encuentre diferente.
Mira, ahora sí que lo ha hecho una vez.
O sea que ahí, bien.
Ahora, movemos este.
Quitamos este.
También en mayúscula.
¡Guau!
¿Qué os parece?
¡Qué fuerte, eh!
Bueno, pero lo hemos encontrado.
Pero es muy loco lo que ha pasado, ¿eh?
Sí, sí.
O sea, ese era el problema.
Os voy a contar el problema.
Que me parece súper interesante.
El tema, por algún motivo, el require lo estaba cacheando siendo case sensitive.
Entonces no estaba encontrando el módulo cuando uno era en minúscula y otro en mayúscula.
Entonces se creía que eran dos módulos distintos.
Y al importarlo pasaba eso, que estaba importando dos veces lo mismo.
Al final, utilizar módulos es un pattern.
También es un patrón.
En el que tú confías en que ese módulo solo se vaya a ejecutar una vez.
O sea, este console.log al final solo estuviese una vez.
El hecho que veíamos dos, ese era el problema.
Porque todo este código, claro, se volvía a ejecutar cuando hacía el require.
Y lo que ocurría es que entonces se ejecutaba todo esto y creaba otra vez el esquema.
Nosotros lo que esperábamos justamente es que este módulo fuese como un singleton.
Quiere decir que eso se ejecute una vez y que nos devuelva solo una vez lo que es este, lo que exporta el módulo.
Y no estaba pasando eso.
Hemos aprendido algo, ¿no?
Está bien.
Al final lo interesante de estos problemas es, pues decir, oye, pues lo vamos a encontrar y ya está.
No pasa nada.
Vale.
Vamos a hacer la request.
Funciona correctamente.
Hemos puesto la midu password.
Hemos creado un usuario.
Ahora aquí, pues deberíamos tener un usuario.
Sin ningún problema.
Sigue funcionando nuestro servidor por ahora.
Pues hará que ya tenemos nuestro usuario creado.
Como midu dev, con nombre Miguel, la midu password.
Importante la midu password.
Vamos al de login.
Y en login, pues nada.
Vamos a hacer lo mismo, solo que en lugar de api barra users, vamos a hacer api barra login.
En principio, ¿qué es lo que esperaba?
Que ahora con todo este ajetreo, lo que esperaba, lo que esperamos aquí es el username y el password.
Solo es eso.
Así que el name lo podemos quitar.
Guardo esto.
Voy a darle a send request.
Y esto es que ha ido bien.
Esto significa, me ha devuelto exactamente lo mismo.
Quiere decir que se ha logueado bien.
Ha hecho un inicio de sesión, digamos.
Que no es exactamente un inicio de sesión.
Se ha logueado bien.
Si yo cambio el password y vuelvo a darle a send request, invalid user or password.
Esto es justamente lo que esperaba.
401 es el correcto.
Quería ver aquí que era no autorizado.
Perfecto.
Al menos ya hemos avanzado esto.
Voy a tirar esto para atrás porque creo que sea el correcto.
Y vamos a volver a trabajar en nuestra ruta de login.
Porque esto está bien en el sentido de que sí, ya estamos haciendo el match de la contraseña.
Se está hasheando y todo esto.
Pero todavía no seríamos capaces de conservar la sesión del usuario.
De decir, este usuario está autenticado en nuestra aplicación.
Esto lo haría una vez, pero no persistiría.
Para hacer esto, hay un montón de sistemas en los que se puede hacer.
Pero el más típico de todos es utilizar JSON Web Tokens.
Que al final es un estándar de la industria.
Que lo que hace es que dos partes se puedan comunicar de forma segura a intercambiar información.
Pero lo más interesante de eso no es solo que intercambias información.
Es que no necesitas como tal, por ejemplo, una base de datos que también lo puedes hacer.
Pero es totalmente agnóstico a donde lo puedas guardar esa sesión.
Al final, una vez que tienes guardada y tienes esa información, tú sin necesidad de persistirla en algún sitio, aunque lo puedes hacer,
puedes indicar dentro de ese token el usuario que es, información que te pueda interesar,
y tenerla codificada y de una forma que es muy difícil falsificarla.
Porque está firmada digitalmente.
Y ahora veremos exactamente qué quiere decir esto de que esté firmada digitalmente.
Aquí tendríamos, por ejemplo, un JSON Web Token.
Aquí tendríamos las tres partes en las que se basa el token.
La parte roja es la que se llama el header, que tiene la información sobre el algoritmo y el tipo del token.
Luego tendríamos la parte lila, que al final es como la información que queremos guardar en este token.
En este caso, aquí tendríamos este objeto con la ID y con el nombre.
Pero tú le puedes poner aquí lo que quieras, siempre y cuando sea información que puedas guardar en formato JSON.
Por ejemplo, podríamos poner algo y poner isAdmin, por ejemplo.
O el número que queramos de sus favoritos.
No es que sea súper útil normalmente, porque hay otras formas de hacerlo, pero se puede hacer.
Aquí le puedes guardar toda la información que quieras.
Y al final hay una parte que es la que te ayuda a verificar que la firma es correcta.
Y de hecho, esta firma es lo que decimos que está firmada digitalmente y depende de un secreto que tú tengas en tu parte en el backend.
Así que falsificarla es muy difícil.
No significa que no sea imposible de hackear y más cuando alguien tiene acceso a este token.
Una vez que alguien tiene acceso físico a este token, guardes donde lo guardes, está jodido.
Porque al final este token es justamente el que verifica de alguna forma que tú tienes la sesión.
Si alguien puede copiarse el token que has usado, entonces ya sí que tienes un problema.
Se pueden hacer diferentes capas para evitarlo, como por ejemplo, que dentro del backend no solo mire cierta información como esta,
sino que mire la localización en la que se ha utilizado este token.
Por ejemplo, si alguien ha iniciado la sesión y le ha devuelto este token y cuando inició la sesión estaba en Barcelona
y de repente alguien que está en Cancún utiliza el mismo token, pues esto seguro que lo habéis visto en un montón de ocasiones en alguna página,
sobre todo Google y webs grandes lo suelen hacer de, ¿has sido tú el que ha iniciado sesión? ¿Estás seguro?
Pues muchas veces también se puede hacer por esto, ¿no?
No solo la información que vemos aquí te puede permitir asegurarte que el token es realmente de esa persona.
Y por eso muchas veces te pueden decir, vale, pues mira, este token que ya no me fío mucho porque a lo mejor te lo han robado,
pues ahora te tienes que volver a iniciar sesión para asegurarme y te voy a devolver otro token.
Al final, aquí para verificar, en nuestro caso, no vamos a hacer algo así tan bestia porque es increíble,
en nuestro caso, en este token que está codificado en Base64 y que tiene toda esta información que vemos aquí,
lo importante es esto, la palabra secreta, que puede ser la palabra que queráis.
Obviamente, cuanto más complicada, pues mejor.
Pero esta palabra secreta tiene que ser, como dice la palabra, secreta, ¿vale? Muy secreta.
Porque ahí es donde radica realmente la imposibilidad de poder firmar o decodificar la firma.
Una vez que tienes esta firma, que solo la deberías tener en la parte del backend, pues ya tus tokens no sirven para nada.
Ya estás también, de nuevo, fastidiado.
Así que, importante, el token este, el secret, hay que cuidarlo y cuidarlo bien.
Vale, pues esto es lo que vamos a utilizar para, justamente, la sesión del usuario.
Vamos a ver cómo funciona exactamente esto, cómo lo podemos hacer en la parte de Node en el backend.
Vamos a nuestra ruta.
Y para ello, lo que vamos a hacer es utilizar primero un paquete que es JSON Web Token,
que es de AUT0, si no me equivoco.
Info JSON Web Token.
Si no es de AUT0, sí, ¿veis? AUT0.
¿Vale? Así que vamos a instalar este paquete, JSON Web Token.
JSON Web Token, ¿por qué? He llamado todo el rato JavaScript Web Token.
Lo vamos a instalar en nuestro servidor, que es el que vamos a utilizar.
Hay diferentes, ¿eh? Hay uno que se llama Hason, hay diferentes.
Pero este, yo diría que es uno de los más utilizados, de sobra comprobado que funciona,
así que no inventemos.
Vamos a nuestro controlador, ¿vale?
En nuestro controlador, lo que vamos a hacer lo primero, pues nada, recuperar este...
Le podemos poner JSON Web Token en cortito, así que vamos con ello y vamos a importarlo.
JSON Web Token.
¿Qué tenemos que hacer con el JSON Web Token?
Vale, pues una vez que ya sepamos, uno, aquí he puesto esto y ahora me estoy dando cuenta
que también tenía que haber puesto que si el usuario, si el usuario no existe, ¿no?
Y si el usuario existe y el password es correcto, guay, pero si no, ¿vale?
Lo hacemos así, porque si no, también teníamos problemas.
Tiene que ser si el usuario no existe y si la contraseña no es correcta.
Y por eso lo negamos todo.
Vale, una vez que sepamos que sí que existe, ¿no?
Y que es correcto, vamos a guardar información en este token del JSON Web Token que os comentaba antes.
¿Qué información vamos a guardar?
Bueno, pues aquí tenemos ya parte, ¿no?
Esta parte que hemos puesto aquí.
Vamos a poner esto por aquí.
Aquí tendríamos cierta información.
Podríamos poner user for token y esto sea la información.
Name, username.
No es tan importante el name, pero lo que sí que sería importante es la ID del usuario.
¿Por qué?
Más adelante veremos por qué es importante tener en el token la ID del usuario.
Así que esto sería lo que vamos a guardar como payload, como ese data que íbamos a tener en el token disponible.
Ahora que tenemos este user for token, lo que tenemos que hacer justamente es crear el token.
Es firmar el token.
Para ello, ahora mismo lo vamos a hacer fácil.
Vamos a crear el token y lo que hacemos es jsonwebtoken.
Y ahora utilizamos sign de firmar.
Y le decimos que queremos firmar este objeto, el user for token.
Y ahora le deberíamos decir cuál es la palabra secreta.
Entonces, por ahora, vamos a poner como palabra secreta 1, 2, 3 y ya está.
Pero luego lo arreglaremos y veremos por qué no lo tenemos que hacer así.
¿Qué es lo que tenemos que devolverle?
Básicamente, ¿cómo responder?
Teníamos el name, teníamos el username, pues ahora además podíamos devolver el token.
Porque este token que vemos aquí es como hemos visto esto.
Este churro que parece difícil de leer.
Y es que está bien que sea difícil de leer.
Aunque tampoco es que esto lo haga mucho más seguro.
Es una forma de codificar y punto.
No es que esto como tal le dé seguridad.
En realidad lo que le da seguridad es codificarlo a través de esta palabra secreta.
Una vez que, si tú has cambiado a palabra secreta, puedes ver cómo parte de esto está cambiando.
Qué es lo que está verificando.
Es la firma digital.
Firma digital.
Vale.
Pues aquí tendríamos el token.
Se lo devolveríamos aquí.
Con esto ya tendríamos nuestro token.
Así que vamos a probar.
A ver si hago un login.
Y con esto, la midudev, la midupassword, a un sendrequest.
Y aquí podemos ver que ya me devuelve el token.
Ya tendríamos el token, este string, que nos está diciendo que este usuario tendría el token.
Aquí tendríamos la información.
Pero lo importante es que necesitamos esa palabra secreta para poder ser capaz de decodificar esta información.
¿Vale?
Entonces, ahora que ya tenemos esto, vamos a ver qué más nos queda.
Vale.
Hay un tema importante.
Claro.
Si por lo que sea, en este caso.
A ver.
Si por lo que sea.
Aunque...
Vale.
No, no.
Estaba pensando.
A ver si vamos a intentar crear el token.
Es importante poner el secret porque si no ponéis el secret, esto puede petar.
Creo que o peta.
¿Ves?
Un error 500.
O sea que, de alguna forma, está bien porque es obligatorio tener un secret.
Lo ideal de esto, pues, es tenerlo en una variable de entorno.
¿Por qué?
Primero, porque lo vas a poder reutilizar en más de un sitio.
Y lo segundo, porque además, ahí en diferentes entornos podrás tener secretos distintos.
Así que, lo que voy a hacer, me voy a ir a mi archivo, este punto env, que es donde tengo las variables de entorno.
Me lo voy a mover.
Voy a poner ahí el secret.
Voy a poner uno secret.
Que va a ser siempre el mismo, ¿vale?
Voy a poner esto por aquí.
Ya lo he puesto.
Que no es importante que veáis el secret.
O sea, es indiferente.
Vosotros podéis poner el que pongáis.
Y aquí ya, process.env.
Y aquí, la variable de entorno.
La variable de entorno ya estamos utilizando en diferentes sitios.
Creo que por aquí tenemos que tener.
Teníamos para el puerto.
Teníamos para el MongoDB.
Pues ahora tenemos uno.
Yo lo llamo secret.
Le podéis llamar como queráis y como prefiráis, ¿vale?
Lo importante es que lo tengáis.
Y que luego lo podáis utilizar.
Ahora que tenemos esto, lo que necesitamos es limitar quién puede crear realmente las notas, ¿no?
O sea, no podemos...
Ahora que tenemos una forma de indicar el token, tenemos que utilizar el token.
Y lo vamos a utilizar para evitar que cualquiera pueda crear una nota.
Queremos que sea un usuario, que tengamos la seguridad que es un usuario, el que pueda crear la nota.
Así que vamos a hacer otra vez el login.
Y vamos a ver que tengo aquí el token.
Y este token es el que necesitamos leer.
¿Cómo se hace esto?
Vale.
Hay otras formas.
Hay un montón de formas de hacerlo.
Pero la forma más correcta es permitir que nuestros endpoints reciban esta información por una cabecera HTTP.
Por un header.
En este caso hay una cabecera justamente que te brinda esta funcionalidad exactamente.
que se llama Authentication.
Authentication o Authenticate.
Authorization.
Authorization creo que es, ¿no?
Ahí está.
Mira.
Authorization.
Aquí vemos un poco lo que hemos visto antes.
Pero básicamente esta header, Authorization, es el que vamos a enviar el token de forma que lo leeremos.
Y diremos, vale, pues ahora vemos que funciona correctamente.
La forma de enviar esta cabecera, ya os digo que hay un montón de formas.
Yo diría que esta es la más típica, la que vamos a ver ahora.
Pero aquí, en MDN, puedes encontrar que hay diferentes esquemas de autenticación.
No vamos a utilizar el Basic porque el Basic ya hace mucho tiempo que está totalmente deprecated.
Que lo que hacía el Basic es que tú enviabas el username y el password directamente en el header en base64.
Bueno, esto obviamente no es muy correcto.
Lo que vamos a utilizar es el Bearer.
Que este es justamente el que utiliza estos tokens de acceso que están, bueno, basados en OAuth 2.0.
Que es un servicio, es una forma, es un patrón o es, digamos, es como un conjunto de reglas para hacer autenticación y sesiones de usuario de una forma bastante segura.
Este sería el que vamos a utilizar.
Pero ya veis que hay diferentes y no solo esto.
Mira, este de hecho es uno que es exactamente solo para Amazon.
O sea, esto es uno que creó Amazon.
Así que os podéis encontrar esto de diferentes formas.
¿Por qué?
Porque a lo mejor no solo necesita la cabecera de autorización, sino también le tienes que pasar más cabeceras que tengan que estar firmadas.
Bueno, hay diferentes formas.
Por supuesto, el token se lo podríamos enviar como parámetro.
No es lo ideal, sobre todo cuando HTTP ya nos da unas herramientas para utilizar a la hora de enviarle tokens.
Así que vamos a utilizar, enviar la cabecera utilizando este de aquí, el Bearer.
Ahora, cada uno está totalmente documentado y tiene una RFC donde te dice todo lo que tiene que cumplir para que sea correcto y tal y tal.
Pero bueno, lo importante es que vamos a ver un poco cómo deberíamos hacer este envío de cabeceros y cabeceras y cómo lo deberíamos utilizar en el backend.
Así que vámonos al backend.
Ya teníamos la de login.
Hemos dicho que vamos a ir a las notas, donde estábamos creando la nota.
Vamos a borrar todo esto.
Bueno, un momento que me voy a copiar antes de seguir.
Me voy a copiar en request.
Me voy a copiar este, ¿no?
El token que aparece porque si no, no sé si me lo he copiado antes, pero que no se me olvida.
Así que ahora en las notas lo voy a pegar y luego lo uso y os explico cómo hay que utilizarlo correctamente.
Por ahora lo dejo así.
Vámonos al index.
Index aquí, donde creamos la nota, en el punto post.
Espero que esto funcione de la última vez que lo dejamos porque tocamos un montón de cosas.
Voy a hacer las cosas más pequeñas.
Espero que vosotros lo tengáis en un controlador porque yo aquí ya tengo un montón y ya os dije que no me gustaba mucho.
Lo primero, por supuesto, es utilizar el JSON Web Token.
Hacer un required de JSON Web Token.
Vamos a necesitar esto para leerlo.
Esto por un lado.
Y ahora, lo que hacemos aquí en este post, que es cuando creamos una nota, lo primero que tenemos que hacer es recuperar el token.
Como hemos dicho, se lo vamos a enviar con una cabecera HTTP.
Por suerte, no lo vamos a hacer aquí directamente.
Que esto sería enviárselo en el cuerpo de nuestra petición.
Sino que lo vamos a hacer por cabecera.
Y para recuperar una cabecera, lo que podemos hacer es poner Authorization.
Y en la request, hacemos un punto Get y ponemos Authorization.
Esto lo que hace, básicamente, es que va a recuperar la cabecera Authorization.
Esto es una cosa de Express.
Se podría hacer a mano.
Creo que en el request también tienes punto Headers, punto no sé qué.
Pero esta sería la forma más corta.
Probaremos si esto funciona correctamente.
Y si no, veremos.
Una vez que tenemos la autorización, lo que tenemos que decir es, vale, si tenemos la autorización.
Y además, tenemos que asegurarnos que la autorización que está utilizando el usuario para intentar crear la nota es la correcta.
Así que la autorización la pasamos a lowercase y vamos a ver si está siguiendo el esquema que estábamos viendo aquí.
Authentication.
Para seguir el esquema, en el de Bearer, este, a ver si, vale, aquí no aparece.
Pero al final, lo que hay que hacer es, primero, indicar el esquema y luego pasarle el payload.
Así que lo que tenemos que saber es que debe ser algo así.
La cabecera que nos tiene que llegar, y lo veremos ahora, debería ser Bearer y luego, pues, bla, bla, bla, bla, bla, que será el token.
Esto sería, ¿no?
Así que lo que tenemos que asegurarnos es que la autorización, si la pasamos a lowercase, porque este Bearer no lo pueden pasar de lowercase, en mayúscula,
en principio debería ser así.
Pero, bueno, así nos evitamos problemas.
Lo que vamos a ver es que, cuando autorización la pasamos a lowercase, tenemos que ver que empieza con la palabra Bearer.
De esta forma nos aseguramos, ¿vale?
Que la autorización que está intentando el usuario es la correcta.
Si este es el caso, lo que podemos hacer sería, por ejemplo, tener aquí, vamos a poner aquí el token, vamos a poner que esto es vacío.
Entonces, ¿cómo vamos a recuperar la autorización?
Pues ya os he dicho que esto empieza en 1, 2, 3, 4, 5, 6, 7, ¿no?
Y queremos justamente el token que empieza aquí, ¿vale?
Esto puede ser cualquier número.
Pues podemos utilizar un substring.
Podemos hacer token es igual a authorization punto substring 7.
Esta sería una forma.
Hay otra, podríais, por ejemplo, hacer un split del espacio y quedarte con el segundo, lo que queráis.
Esta es la que, por ejemplo, sale en full stack open.
Podríais, si os gusta más, pues hacer la del split.
Si no, el token sería el segundo.
O sea, deberíais recuperar esto.
El que prefiráis, el que os parezca más claro.
Esto sería la forma.
Vamos a poner un null para asegurarnos que somos capaces de detectar mejor esto.
Una vez que tenemos el token, el token, como hemos visto, esto al final era un string como tal, ¿vale?
Es un string, no tiene, o sea, tiene el token, pero todavía no tenemos acceso a la información.
Porque hemos dicho que tenemos que decodificarlo.
Para decodificarlo, para tener la información decodificada, tendríamos que poner aquí decode token.
Tendríamos, otra vez, el JSON web token y vamos a verificar realmente que este token lo podemos volver a abrir con el secret.
Aquí se me ha olvidado esto.
Ahora, no lo vaya a liar.
Y esto lo voy a quitar de aquí también.
Entonces, aquí tendríamos el token decodificado con toda la información y tal.
Antes, justamente, de seguir, podríamos ver, ¿no?
Si no tenemos token o el token decodificado.
No tenemos la ID del usuario, que si volvemos aquí al login, estábamos en el token guardando la ID, ¿vale?
La estamos recuperando y la estamos guardando.
Si no tenemos token y no tenemos el token decodificado, pues esto lo que significa, pues que no tienes acceso.
Así que hacemos un 401, JSON, un error y le decimos que el token está falta o es inválido.
Y con esto se supone que deberíamos tener ya el hecho de controlar que no se puede crear una nota si no tienes el token.
De hecho, vamos a intentarlo.
Vamos a ver si esto funciona, si no se me ha olvidado nada.
Request, postnote.
Este es el token que vamos a utilizar ahora.
Por ahora lo voy a dejar así.
Vale, y vamos a intentar hacer un send request a ver qué pasa.
Vale.
Espera, esto ha petado porque, ¿qué he hecho?
Me he equivocado a las JSON web tokens.
Es que no es, perdón, ¿eh?
Esto no es así, no se importa así.
Es, ¿cómo era esto?
JSON web token, así.
Ahora sí.
He puesto un nombre que no era.
Por eso se había caído el servicio.
Vamos ahora.
A ver.
Si yo ahora envío una request sin token ni nada.
Vale.
Nos da un error 500 que no es exactamente lo que estábamos esperando.
Así que vamos a ver qué es lo que pasa.
Vamos a ver qué es lo que ha pasado por aquí.
Vamos a ponerle unos chivatos a ver si nos dice algo.
Esto es el postnote.post.
Vale.
Tenemos aquí todo esto.
Tendríamos la autorización por aquí.
Esto debería estar funcionando, pero igual hay algo.
Authorization.
Lo he escrito bien.
No lo voy a liar.
Si no tengo token, esto es null.
Esto es substring.
Estamos verificando con el process.net.secret.
Esto tiene un retón que no se nos olvide.
Es que el error 500 normalmente es porque el user ID no lo está encontrando.
Claro.
Exacto.
Pero claro, todavía no debería estar pasando por aquí.
No, ya está pasando por aquí.
Token, decoded token.
Vamos a poner esto por aquí.
A ver qué le pasa.
A ver qué le pasa.
Vale, esto...
Vamos a crear...
Vamos a enviar una request.
Vale.
Es que nos está dando un undefined aquí.
En el authorization.
Claro.
Es que, claro.
¿Cómo hacer un get de autorización si no está...?
Claro, claro.
Obviamente autorización todavía no tengo.
Lo que pasa es que pensaba que a lo mejor esto no nos petaría.
El hacer esto todavía no nos iba a petar.
Sino que nos iba a permitir, ¿veis?
La autorización no existe.
Y esto está dando un error 500 en algún punto.
Seguramente si estamos a autorización...
O sea, aquí no entra.
Me imagino que es aquí, en el decoded token, que si le pasamos null, no le está gustando esto.
Podríamos...
Podemos adaptarlo un poco, ¿eh?
Para que esto funcione un poco mejor.
Vale.
Before...
Claro, lo que está petando es esto, ¿no?
Que este token...
Mira aquí.
Cuando hacemos el verify de este token, esto no funciona tal cual.
Yo pensaba que esto a lo mejor notaría un null y ya está.
Pero no.
Entonces, pues nada.
Tenemos que arreglarlo.
Una forma, entiendo que podríamos poner esto.
Y esto en principio debería funcionar.
O sea, utilizamos un string vacío.
Ah, no.
No, también.
O sea, que esto está...
Token...
Porque es verify, ¿no?
A ver si le ha liado parda y he puesto otra cosa que no es.
Pero sí, es verify con el token y tal.
A ver.
Try.
Vamos a poner un try catch.
Y nos vamos a quedar a gusto.
A ver si es esto.
Esto.
Decoded token.
El decoded token ahora lo tenemos que poner fuera.
Voy a mirar primero cuál es el error.
Que está tirando esto.
Porque está claro que ahí hay un error.
Vale.
JSON web token must be provided.
Claro.
O sea, el problema es ese.
Básicamente.
El problema es que no estoy basando una autorización.
Lo que pasa es que pensaba que al menos, de alguna forma, funcionaría.
Y no tendría que ser tan, tan bestia.
Una cosa que podemos hacer, pues nada.
El decoded token.
Ponerlo aquí como un...
Un objeto.
Hacer esto.
Luego lo...
Ya lo revisaremos.
A ver.
Cómo lo podemos hacer un poco mejor.
Pero en principio...
Vale.
Esto.
Esto que sea LED.
Y esto lo guardamos así.
Y esto en principio...
Pues sí.
Vamos a tener aquí el console error.
De que le hemos pasado un token y tal.
Pero prefiero por ahora que lo controlemos así.
Que pongamos un 401 y le digamos, oye, que falta el token o que está missing.
Y ya está.
Vamos a probar ahora.
Bueno.
Vemos el error.
Pero al menos, ¿veis?
Sí que pone token missing or invalid.
Bueno, esto tiene más sentido.
A lo mejor no hace falta ni siquiera el tener que validar el error.
Si ya sabemos esto.
Pero bueno.
Me hubiera gustado.
O yo por hecho que esto se iba a tragar cualquier cosa.
Y el decode token me iba a dar vacío o lo que fuese.
Ya veo que no.
Eso me pasa por fiarme.
Bueno, no pasa nada.
El tema.
Que ya lo tenemos arreglado.
Que ya estamos controlando mejor esto.
Que falta el token.
Y esto es lo que vamos a solucionar.
¿Cómo enviamos el token?
Bueno.
Pues en realidad es bastante sencillo.
Estos son las cabeceras.
Los headers.
Ya sabéis que aquí en las clases de FullStack Bootcamp.
Estamos utilizando a muerte esta extensión de Visual Studio Code.
Porque es bastante útil.
Tienes documentadas todas las requests.
Nos permite probar rápidamente las cosas.
Este sería el cuerpo.
El payload que le estamos enviando al post.
Y podemos ponerle también los headers.
Y aquí en los headers podemos poner autorización.
Y justamente.
Claro.
El problema es que ahora he perdido.
Como he estado copiando cosas.
He perdido el del login.
Pero bueno.
Me logueo otra vez.
Copio el token.
Y vamos otra vez al del post.
Vamos a poner authorization.
Y aquí.
Ojo.
Cuidado que este es un error muy típico.
No.
O sea.
Hemos pegado directamente el token.
Pero esto no es lo que tienes que hacer.
Es parte de lo que tienes que hacer.
Hemos dicho.
¿Qué?
Le tenemos que indicar cuál es el esquema de autorización que utilizamos.
Así que no se te olvide viewerer.
Este es el típico problema muchas veces de por qué no le funciona y tal.
Lo puedes poner con minúscula.
De hecho.
Veis que aquí pone basic row.
No sé qué.
No sé cuánto.
O sea que.
Pero.
Pero.
Yo os recomiendo que lo hagáis así.
¿Vale?
El primero en mayúscula y luego el token.
Y esto ahora sí debería estar funcionando.
Vamos a ver qué pasa con esto.
Vale.
Un error 500.
Perfecto.
Pues vamos a ver qué le pasa ahora con el error 500.
Igual es.
El proceso.
O sea.
Igual sí que hay algo aquí que no le está gustando del todo.
Pero bueno.
Vamos a tirar para atrás.
Otra vez esto.
Pero al menos ya nos estamos acercando al tema.
Me sorprende.
Voy a leeros.
A ver.
Que normalmente estáis súper.
Decoded token and.
No token and.
Bueno.
Está aquí.
Ahí no ha llegado todavía el código.
A ver.
¿No sería más práctico crear un middleware?
Sí.
Claro.
Señor Dead.
Vamos poco a poco.
Haremos el middleware.
¿Vale?
Pero claro.
Si todavía no.
No tenemos.
No funciona esto.
Vamos a hacer el middleware después.
Creo que el import del WT está mal.
Ah.
Puede ser que esté el import mal.
Sí.
No.
Ya lo hemos arreglado.
No.
Ya lo hemos arreglado el import.
¿No?
Mira.
Me lo voy a copiar del login.
Que sé que funciona ese.
Pero sí.
Sí.
Sí.
El import.
El import ya está hecho.
Vale.
¿Hay algún error por aquí?
Vamos a averiguarlo.
No pasa nada.
Vamos a ver.
Porque es bastante raro.
No.
Aquí veis que tenemos ya.
Tenemos.
O sea.
Sí que lo está decodificando.
Aquí sí que lo está decodificando.
Tenemos el decode token.
Vale.
Ya sé cuál es el error.
Ya sé cuál es el error.
Ya sé cuál es el error.
No es problema nuestro.
Esto está funcionando bien.
El problema está en realidad en el ID del usuario.
Porque cuando creamos una nota.
¿Veis que teníamos aquí un user ID?
Claro.
Teníamos aquí un user ID.
Pero este user ID no existe ya.
Porque lo he borrado antes.
Entonces.
En realidad ni siquiera nos tenemos que fiar ya de este user ID.
Este user ID ya no tiene sentido.
Vamos a quitar este user ID.
Este es el problema.
Que está intentando buscar este user ID.
Mirad.
Aquí cuando haces un fan by ID.
Y tú le pasas un user ID.
Un ID y tal.
Y esa ID no la encuentra.
Esto peta.
Lo que tendríamos que hacer para evitar que petase.
Es find one.
Y decirle la ID y tal.
Y entonces te devuelve null.
Pero si tú le dices find by ID.
Y le pasas la ID.
Y no existe.
Te peta.
Es muy raro.
Pero lo hace.
Y esto es lo que está pasando.
De hecho.
Tiene sentido.
Porque es que ni siquiera tendríamos que pasarle este user ID ya.
Esto lo vamos a eliminar.
Porque esta información.
¿Ves?
Esta información ya la tengo aquí.
La tengo en el token que estoy decodificando.
Así que.
Este token que estoy decodificando.
¿Vale?
Si no tengo token.
Y o no tengo decoded token ID.
¿Vale?
Pues token missing or invalid.
Pero una vez que estoy aquí.
Una vez que estoy aquí.
El ID.
El user ID.
Esto lo tengo que sacar del decoded token.
Este user ID.
Ya no lo tengo que recuperar del request body.
Esto ya no tiene sentido.
Lo tengo que sacar directamente del token.
Porque si no.
¿Qué sentido tiene el token?
Así que.
Lo que hacemos es esto.
Del decoded token.
Que veis aquí.
La información que tenemos del decoded token.
Tenemos la ID.
El username.
Y el IAT.
Que el IAT.
No.
No.
No es algo que hemos puesto nosotros.
Pero.
Lo que quiere decir es.
Isuit add.
Es como un timestamp.
De cuando se firmó digitalmente.
¿Vale?
Este token.
Entonces.
Aquí ya tenemos la ID.
Vamos a fiarnos de esa ID.
Que es la que se supone que nos está pasando.
Debe ser un usuario que debe existir.
Porque si le pasamos uno aquí.
Podríamos hacer que reviente muy fácilmente.
Tenemos que fiarnos más del token.
Y siempre.
Mirar token.
Token.
Token.
Que igualmente en el token también.
Sería raro.
Llegar a tener un ID de usuario que no existe.
Pero bueno.
Podría pasar.
También habría que revisarlo.
Bueno.
Vamos a hacer el post.
Otra vez.
A ver.
Ahora sí.
Ahora sí que ha funcionado.
¿Vale?
¿Por qué?
Pues porque tiene el token de autorización.
Porque hemos encontrado por fin la ID del usuario.
La correcta que teníamos en el token.
Porque ha iniciado sesión.
Y mientras tengamos este authorization.
Este token.
Yo puedo hacer aquí notas.
Como no era mañana.
Y aquí pues ya tendríamos una.
Que hemos suscríbete a mi du dev.
Ahora aquí pues puedo poner otra.
Otra nota más.
Con este token.
Lo importante.
Pues que este de token.
Tú lo tengas guardado.
Mientras tengas este token.
Pues vas a poder estar haciendo aquí.
Pues como si no hubiera mañana.
Vale.
¿Qué más podríamos hacer?
Claro.
Ahora si yo cambio un poco.
Por ejemplo.
Quito PC.
¿Veis que aquí que tengo dos letritas?
Si yo las quito.
Le estoy enviando un token que no es correcto.
A ver.
Voy a hacer un send request.
Vale.
Me está haciendo este token.
Misión y no mi valid.
Bueno.
Pues esto es justamente lo que queríamos o lo que esperábamos.
Que nos verifique esto y ya está.
Entiendo que una cosa que podríamos hacer cuando teníamos esto.
En realidad.
O sea.
Cuando le poníamos dos.
Y teníamos aquí el try, catch y todo esto que le he puesto.
Esto de aquí.
Voy a probar una cosa.
Porque creo que a lo mejor podemos manejar esto de una forma más inteligente.
Vamos a probar esto un momento.
Le he quitado dos letras.
Ahora si doy esto.
Vale.
Me da un error 500.
Pero este error 500 en realidad seguramente es porque en el error handler no lo estamos controlando.
¿Veis?
Que teníamos aquí error name, error name.
Esto tiene que tener su propio error name.
Que debe ser JSON web token is not valid.
Algo así.
Entonces lo que vamos a hacer aquí yo creo que es mejor.
Ya os dije que lo ideal sería tener en un solo sitio.
Vale.
¿Veis?
JSON web token error.
Así que en lugar de tener un error 500 aquí.
Pues esto.
Aquí podemos hacer el shift, el shift.
Pues aquí todo el rato.
Si es un error name.
Pues esto.
Si no.
Si es un error name.
De hecho esto ahora lo vamos a cambiar un poco.
¿Vale?
Y lo vamos a dejar mejor todavía.
Primero voy a hacer esto.
Asegurarme que esto lo dejamos bien.
Que lo que queremos aquí es lo que estábamos haciendo aquí.
Que si no sé qué, no sé cuánto.
Bueno.
Pues algo así parecido debería ser.
Aunque no es missing.
Ya sería invalid directamente.
Pero sería esto.
Teníamos que hacer un response status.
Con token missing.
De esta forma no dejamos ese error 500 que no es nada descriptivo.
De hecho.
Pues mira.
Voy a dejar esto.
Error name por aquí.
Para que nos chive si vuelva a ocurrir un error 500 que no es muy descriptivo.
Al menos que veamos ahí la consola.
Que no es lo chive.
Pero creo que esta puede ser la mejor forma.
¿No?
Tenerlos aquí y tal.
Una cosa para evitar este.
A mí esto.
A mí esto me pone nervioso.
A mí esto me pone nervioso.
A mí una forma de controlar este tipo de cosas.
Hay gente que diría.
Pon un switch.
A mí tampoco me gusta mucho el tema de los switches.
Lo que podemos tener como.
Al final es como un diccionario.
Entonces podríamos tener error handlers aquí.
¿Vale?
Y lo que podríamos pasarle aquí.
Pues error handlers.
Podría ser un objeto por ejemplo.
Y que el cast error.
Pues esto le tengas que pasar la response.
Y ya directamente tengas esto.
¿Vale?
¿Cuándo es esto?
Esto.
Cuando es un cast error.
Pues esto.
Cuando es un validate error.
Pues esto.
En este caso hay que pasarle también el error.
Pero bueno.
Se lo podríamos pasar.
Podemos pasarle response y error.
Response.
Total.
Si no lo necesitamos.
Pero creo que puede ser un poquito más fácil.
A la hora de mantenerlo.
Que hay con tanto if y tanta leche.
Es un poco raro.
Esto no lo necesitamos.
Y así todo el rato.
Y así todo el rato.
¿No?
Validation error.
El json web token error.
Y esto.
Es que al final.
Más adelante.
Pues seguirán saliendo otros.
Y pues nada.
Response y error.
También.
Bueno.
En este caso tampoco necesitamos el error.
Pero bueno.
Y.
Ta ta ta.
Pues esto.
Y si no.
Pues el default error.
Que esto.
Puede ser.
Con el response.
Response.
Bueno.
He puesto response.
Pero normalmente se utiliza res.
Porque es un poquito más corto.
Así que podríamos cambiar todo esto.
Por res.
Res.
Res.
Res.
Res.
Vale.
Ahora le ponemos las comas.
También.
Importante.
Y lo podemos separar.
Un poco.
Para leer mejor cada uno.
Y ahora.
En lugar de todo esto.
Lo que podríamos hacer.
Es.
Recuperar el handler.
Con el.
De los.
Error handlers.
Le pasamos el error.
El error punto name.
Y si no.
El error handlers punto.
Default error.
Y ahora en el handler.
Le pasamos la respuesta.
Le pasamos el error.
Bueno.
Yo he hecho aquí un refactor.
Porque me ha parecido genial.
Pero.
Algo así.
Podría funcionar.
Uy.
Que pasa.
Ah.
Esto es que a veces.
Cuando uno copia.
No le gusta.
Pero algo así.
Algo así.
Podría funcionar.
Vamos a quitar el error.
Donde no tienen sentido.
En este si que tiene sentido.
Si que se lo vamos a dejar.
De hecho.
Esto podemos hacer así.
Y al menos.
Un poco mejor.
Y dejarlo en una sola línea.
Y bueno.
Creo que se puede.
Que está mejor.
Como más separado.
De que solo recuperar.
Pues el handler que tienes que ejecutar.
Y ya lo tendrías.
Y ya está.
El día de mañana.
Que tienes que añadir un error.
Pues nada.
Buscas aquí.
Error handler.
Y vale.
Pones el nombre del error.
Y luego.
Como lo tienes que manejar.
Y ya está.
Podría ser una forma.
Esto es una idea mía.
Y.
Si lo consideráis bien.
Y si no.
Lo podéis hacer de cualquier otra forma.
Que os guste más.
Y ya está.
Esto sería ya.
Para el error handler.
Entonces.
Hay un problema.
Como os he dicho.
Una vez que yo tengo esto.
Una vez que yo tengo este token.
Yo ya soy esta persona.
O sea.
Yo ya soy este usuario.
Una vez que tú tienes este token.
Tú ya te puedes hacer pasar por este usuario.
Como os he comentado antes.
Podéis hacer.
En el backend.
Pues ver.
Que este token.
Tenga una geolocalización.
Para determinar.
Si realmente es el mismo usuario.
Cosas así.
Se pueden hacer.
Diferentes cosillas.
Para ver.
Si realmente es el mismo usuario.
Guardar temas del dispositivo.
¿No?
Del token este.
Lo hemos creado.
A un dispositivo.
Que tenía este user alien.
Claro.
Si yo tengo este user alien.
Pero si tú ahora.
Haces una request.
Con otro user alien.
Pues entonces el problema.
Ya no.
O sea.
Este token no es tan válido.
Puedes intentar.
Guardar información.
Para evitar.
Justamente.
Que alguien te lo robe.
Que es difícil.
¿No?
Pero si alguien tiene acceso físico.
A tu ordenador.
Te lo puedes robar súper fácil.
Sobre todo.
Cuando se guarda en cookies.
Local storage.
O lo que sea.
Al final.
Claro.
Si alguien tiene acceso físico.
A tu máquina.
Muchas cosas te pueden hacer.
Cosas que se pueden hacer.
Para intentar.
Evitar esto.
Se pueden hacer un montón de cosas.
Algunas que os he dicho.
Nosotros.
En nuestro caso.
Una cosa que podríamos hacer.
Es también que expire.
Porque ahora mismo.
Creo que no tiene una expiración.
Como tal.
Entonces.
Lo que se puede.
Es pasar.
Un parámetro aquí.
A la hora de firmar.
Este token.
Le podemos decir.
Oye.
Vale.
Firmamos este token.
Pero la validez.
Que tiene.
Pues es de.
Y le ponemos aquí.
El número de segundos.
Que serían.
Por ejemplo.
60 segundos.
Sería un minuto.
Pues no.
Queremos que sea una hora.
Pues bueno.
En lugar de una hora.
Queremos que sea un día.
Si queremos que sea un mes.
Y le vamos poniendo.
Vale.
Vamos a ir poniendo lo que queramos.
En nuestro caso.
Vamos a poner.
Pues 7 días.
Por poner algo.
Pero esto lo que significa.
Es que.
Tendremos que hacer.
Que nuestro usuario.
Cada 7 días.
Se tenga que volver a.
A loguear.
Le tenemos que decir.
No.
Ya no tienes acceso.
¿Cuántas veces os ha pasado?
¿No?
Que estáis en una página.
Donde habéis estado.
Con la sesión iniciada.
Durante un montón de tiempo.
Y de repente os dice.
Oye.
Que.
Ahora ya.
No funcionó.
Ah.
¿Por qué?
Bueno.
Pues seguramente.
Porque vuestro token.
Ha expirado.
Y tenéis que volver.
A iniciar sesión.
Para que os dé uno nuevo.
Sobre esto.
Pues igual que teníamos.
El JSON Web Token Error.
Sí que sé.
Que esto debía ser.
Token Expired Error.
No lo vamos a hacer.
Porque tendría que forzar.
¿No?
Que sea tal.
Pero bueno.
Solo para que lo sepáis.
Igual que teníamos.
El JSON Web Token Error.
Que hay uno para saber.
Cuando ha expirado.
Esto es bastante útil.
Porque en el controlador.
Podríamos ver.
Si el error es.
Que es inválido.
O que ha expirado.
¿Vale?
O sea.
Tú puedes saber.
Que es un token válido.
Pero expirado.
Eso puede ser interesante.
Porque hay veces.
Que podrías decir.
Bueno.
Pues sabes que.
Ya que ha expirado.
Lo que voy a dejar.
Que sí que haga esta operación.
Porque no es tan crítica.
O lo que sea.
O voy a determinar.
Si sigue siendo realmente.
El mismo usuario.
Revisando cosas.
Lo que sea.
Por ahora.
Decimos aquí.
Que el token ha expirado.
Al menos para tener información.
De por qué no funcionaría algo.
Y ya estaría.
Esto sería un poco.
El tema de.
De tener el token.
Importantísimo.
Sobre el tema del token también.
Todo esto del token.
Cuando se hace.
Esta validación.
Que nosotros estamos enviando.
Este header.
Si estamos haciendo.
Esta comunicación.
Por el protocolo HTTP.
En realidad.
Alguien podría ser capaz.
De copiarse al vuelo.
Este token.
Porque la conexión.
No está cifrada.
Así que bueno.
Bastante importante.
Esto es obvio.
Porque hoy en día.
No deberías utilizar.
En ninguna página HTTP.
Pero.
En localhost.
Podríais utilizar HTTPS.
Para probar.
No pasa nada.
En localhost.
Porque estáis probando vosotros.
No tiene mucho sentido.
Pero en páginas.
Que sean HTTP.
Si alguien tiene acceso a la red.
Podría llegar.
A copiarse al vuelo.
Esta.
Esta.
Este token.
Así que.
Importante.
Vale.
Que tenéis que hacer esto.
Que sea por HTTPS.
Entonces.
Alguien me decía.
En el chat.
No.
Decía.
Bueno.
Pero esto.
No lo haces un motherboard.
Es que la gente.
Tiene una.
Una ansia.
Una ansia.
Claro que se puede hacer un motherboard.
Vale.
Lo que pasa es que estamos haciendo.
Que primero funcionase.
Pero.
Todo esto que hemos hecho aquí.
En realidad.
Además.
Seguramente.
Seguramente.
Lo vamos a necesitar en otros sitios.
Por ejemplo.
El delete.
No.
Teníamos.
No vamos a querer que cualquiera pueda borrar una nota.
¿No?
Pues por ejemplo.
Esto.
Lo deberíamos necesitar.
También en otros sitios.
Una cosa que podemos hacer.
Es.
Crear un middleware.
Que podríamos hacer.
A ver.
Como lo podemos hacer aquí.
Token.
Estoy pensando.
Si token extractor.
User.
Directamente.
Porque se puede hacer como de diferentes formas esto.
¿No?
Y podríamos incluso.
Recuperar.
Todo esto.
Todo esto.
Creo que podríamos quitar todo esto.
Vamos a ver.
Todo esto.
Y aquí.
Sacar.
User ID.
De request.
Vamos a ver si esto tiene sentido.
Lo vamos a probar.
Podríamos hacer un middleware.
¿Vale?
Que sería.
Por ejemplo.
Pum.
Pum.
Pum.
Get.
Get user.
No sé cómo.
Sé que en full stack.
Esto lo hacen.
Pero no sé cómo lo llaman.
Creo que le llaman user extractor.
Vamos a poner user extractor.
¿Vale?
El user extractor este.
Pues mirando nuestros middleware.
¿No?
Que tenemos el not found.
Handle errors.
Bueno.
El not found mejor.
Tenga un model exports.
Esto le recupera un request.
Response.
Y next.
Y aquí podríamos hacer lo que queramos.
Pues ya sabemos.
Model exports.
Igual.
Request.
Response.
Y next.
Y aquí.
Se puede hacer una cosa muy interesante.
Que se puede hacer.
Que tiene express.
Y es el hecho de que.
Ah.
Bueno.
Importante que también.
Vamos a poner bien aquí.
Y esto.
Que si no.
JSON web token.
¿Vale?
Ahí está.
Pues express.
Tú lo que puedes hacer es guardar cierta información.
Que esté en la request.
Una vez que pasa por un middleware.
Tú puedes guardar en la request cierta información.
Y está muy bien.
Porque de esta forma no tienes que preocuparte.
De sacarla de otro sitio.
¿Cómo se hace esto?
Bueno.
Aquí ya teníamos esto.
Request.
Sacamos el author.
Esto funciona exactamente igual.
El decode.
Esto también lo podemos hacer.
El response status.
Pues aquí podemos parar justamente la ejecución de nuestra ruta.
Y decir.
No, no.
Si llegas por aquí.
Pues no sigas.
Responde status 401 y ya está.
Pero es aquí donde está lo interesante.
Una vez que ya tenemos aquí la idea del usuario.
¿Qué podemos hacer?
Pues lo que podemos hacer.
Es decirle que la request la podemos mutar.
Porque al final es un objeto.
Y podemos decirle.
Pues aquí vamos a tener el user ID.
Y el user ID.
Pues es user ID.
Y una vez que tenemos esto.
Pues ya sí.
Vete a la siguiente ruta.
Vete a la siguiente ruta.
Ahora que tenemos esto.
Ya tenemos un middleware.
Que nos está haciendo toda la extracción del usuario.
Está mirando el token.
Todo esto ya lo podríamos reutilizar.
Y para utilizarlo.
Hay diferentes formas de hacerlo.
Una de ellas.
Es que cuando estamos en una ruta.
Cuando estamos en una ruta.
Podemos indicar aquí.
Tantos middleware como queramos.
Antes habíamos utilizado los middleware.
Por ejemplo.
Así ¿no?
Esto era un middleware.
Y lo utilizamos a saco.
Pero ¿qué pasa?
Que ahora necesitamos ser más quirúrgicos.
Necesitamos decirle.
No, no.
Es esta ruta en concreto.
Que necesitas.
Que sea un usuario.
Pues vamos a importar.
Mira.
Esto ya no lo necesitamos aquí.
Pues fantástico.
Vamos a importar el user extractor.
El require.
El middleware.
El user extractor.
Y este user extractor.
Esto es una forma.
Si te fijas.
De hacer rutas privadas.
Pero en nuestro backend.
¿Por qué?
Porque al final.
Solo un usuario.
Que realmente tenga acceso.
A esa ruta.
Que tenga la sesión.
Y que tenga el token.
Podría utilizarlo.
Así que aquí.
Podríamos decirle.
Vale.
Primero.
Utiliza el user extractor.
Y luego.
Vas a ejecutar.
El async.
Este middleware.
Al final.
Se lee de izquierda a derecha.
Vamos a entrar.
A este.
Por post.
Vamos a entrar a esta ruta.
Vamos a ir al middleware.
User extractor.
Ejecutaría todo este código.
Si todo ha ido bien.
Bueno.
Si ha ido mal.
Pues se iría.
¿No?
Por la respuesta 401.
Pero si ha ido bien.
Se iría a la siguiente.
La siguiente.
¿Cuál es?
Pues es esta de aquí.
¿Y qué hemos hecho?
Pues hemos dejado.
En la request.
El user id.
Así que podríamos recuperar.
De la request.
El user id.
Y con esto.
Esto ya lo deberíamos tener.
Vamos a ver si esto funciona.
Si no lo he liado.
Pero esto sería una forma muy interesante.
Porque ahora.
Sería tan fácil.
Como que este user extractor.
También lo ponemos aquí en delete.
Y también lo ponemos aquí en put.
Y estas tres rutas.
Estarían protegidas.
Si no tienes un token de usuario.
No las podrías utilizar.
Y ya en este token.
Además tienes la información.
De cuál es el user id.
Que tienes que utilizar.
Así que.
Perfecto.
Pues entonces.
Esto parece que funciona.
Vamos a probarlo.
Eso sí.
Que si no.
Vamos a request.
Vamos a login.
Voy a logearme.
Para ver si esto sigue funcionando bien.
Tenemos aquí un token.
Que nos lo vamos a quedar.
Ahora.
Me voy a crear una nota.
Al post.
Y vamos a cambiar este token.
Por uno nuevo.
Uy.
Bastante más.
Más largo.
O parece.
Vamos a poner aquí.
Que esto es.
Utilizando.
El.
Middleware.
Del.
User extractor.
Guardamos.
Send request.
Y ha funcionado correctamente.
O sea.
Que ha hecho exactamente.
Lo mismo que estamos haciendo antes.
Pero.
Mucho mejor.
De esta forma ya.
Tenemos el user extractor.
Lo podemos reutilizar.
En cualquier.
Endpoint.
Que tengamos ahora.
O más adelante.
De hecho.
Ya lo he puesto.
Tanto en.
Put.
Delete.
Y post.
Que son los tres.
Que obviamente.
Si las notas.
Están relacionadas a un usuario.
Pues ese usuario.
Debe tener acceso.
Justamente.
Para esa nota.
Así que.
Ya lo tendríamos.
Hecho.
Ya tenemos el user extractor.
Con el.
Middleware.
Ahora.
Que tenemos esto.
Deberíamos irnos.
Y nos vamos a ir.
Al frontend.
Así que.
Vamos a hacer que esta sesión.
La podamos tener.
En el frontend.
Vamos a volver.
De nuevo.
Después de toda esta parte.
De este.
Para que se vea.
Que es un full stack.
De verdad.
Empezamos con el frontend.
Hemos estado.
Unas cuantas clases.
Con el backend.
Y yo sé.
Que estabais echando.
De menos el frontend.
Así que.
Ahora vamos a continuar.
Con el frontend.
Pero antes.
Voy a.
A leer.
A ver.