Login con Angular y Auth0
Tags: angular, auth0, typescript
Published: 2021-04-29 19:45:27

Auth0 es una solución flexible e integrada para agregar servicios de autenticación y autorización a sus aplicaciones.


##**¿Por qué usar Auth0?**

Como mencione anteriormente desarrollar un sistema de autenticación desde cero puede ser bastante complejo. Auth0 es una plataforma de identidad como servicio (IDaaS) que permite centralizar y autenticación y autorización aplicaciones y brindar un sistema de seguridad seguro para sus usuarios y de esta manera reduciendo la complejidad para la seguridad de sus aplicaciones.

Auth0 brinda funciones de seguridad listas para ser usada en sus apps, con Auth0 podrá integrar en sus app inicio de sesión con correo electrónico y contraseña e inicio de sesión social con terceros como (Google, Facebook, Github, etc)


**Contenido**
1. Crear Aplicación de Angular
2. Configurar Angular App en Auth0.com
3. Configuración del Auth0 Angular SDK
4. Autenticar usuario
5. Recuperar perfil del usuario
6. Proteger rutas
7. Conclusión


**Iniciemos**


###**1. Crear Aplicación de Angular**

Lo primero que debemos hacer es crear la aplicación sobre la cual vamos a trabajar, ejecutamos el siguiente comando:

```properties
ng new angular-login-auth0 --routing --style=scss
```

Una vez creada la app accedemos al directorio 

```properties
cd angular-login-auth0
```


###**2. Configurar Angular App en Auth0.com**


Antes de iniciar a integrar el SDK de Auth0 para Angular, tenemos que crear una cuenta en auth0.com y registrar un aplicación de tipo SPA.

Vamos a ir a [Auth0](https://auth0.com) puede ir a la opción de "Sign Up" y crear un cuenta , es super sencillo, también puede iniciar con acceso social con Google o Github.

Auth0 te solicitara la creación de un **Auth0 Tenant** que no es mas que un contenedor que utiliza Auth0 para para almacenar su configuración de servicio de identidad y sus usuarios de forma aislada.

Ningún otro usuario de Auth0 puede ver el tenant que haz creado ni tu puedes ver el de otros usuarios.


Una vez que ha configurado lo anterior, Auth0 lo lleva al panel de administración donde se podrán administrar y configurar todos los servicios de Auth0.


![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nubhccotoc5hs1kfoz58.png)


####**Crear Aplicación en Auth0**

Tenemos que crear una aplicación en Auth0 la cual vamos a conectar con nuestra app de Angular que hemos creado previamente.


En el menu lateral izquierdo vamos, hacemos clic en la opción aplicaciones y luego en crear aplicación.

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4yamzuqus6qwncoz4ckh.png)
 

Para este ejemplo nombre la app como "Angular Login", se debe elegir la opción de Single Page Web Applications ya que estamos trabajando en una SPA con Angular.


Una vez crear la aplicación haga clic en la tab de **settings** aquí es donde esta toda la configuración de su aplicación especifica, incluyendo su ClientId y Client Secret.

####Comunicación entre Angular y Auth0

Cuando se trabaja con Auth0, no es necesario que nosotros creemos un formulario de inicio de sesión, Auth0 ya ofrece una página de acceso universal. Este formulario reduce el riesgos a nivel de seguridad.


![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fwx4r1xm6v0j3nk1ha3b.png)
 

####¿Cómo funciona el acceso universal?


Cuando un usuario intente iniciar sesión en la aplicación de Angular se redirigirá a Auth0 y les mostrar la página de inicio de sesión universal. Para que esa redirección se realice de forma segura, debe especificar en la configuración de la aplicación Auth0 las URL a las que Auth0 puede redirigir a los usuarios una vez que los autentica.


Primero configuremos a donde debe ser redirigido el usuario cuando haya iniciado sesión de manera correcta

En la opción "Allowed Callback URLs" colocamos lo siguiente:



```properties
http://localhost:4200
```


Luego hay que configurar también a dónde debe ser redirigido el usuario cuando haya cerrado la sesión de manera correcta.

En la opción "Allowed Logout URLs" colocamos lo siguiente:


```properties
http://localhost:4200
```


Auth0 solo podrá redirigir al usuario a las URL que haya colocado anteriormente como origenes permitidos.


**Orígenes web permitidos**

Cuando se utiliza el Auth0 Angular SDK, la aplicación de Angular realiza solicitudes bajo el capó a la API de Auth0, esto para manejar las solicitudes de autenticación, es por ello que debe agregar la URL de origen de su aplicación angular para evitar problemas de intercambio de recursos de origen cruzado (CORS).


```properties
http://localhost:4200
```

Para finalizar hacemos clic en "Guardar Cambios".


####Variables de configuración

Para permitir que la Aplicación de Angular se comunique con Auth0 se necesitan los valores de ID de cliente y dominio Auth0. Estos valores están en la "pestaña" de settings

En su aplicación de Angular cree un archivo llamado auth_config.json (A nivel del proyecto)

Este archivo debe contener la siguiente información


```properties
{
  "domain": "YOUR_AUTH0_DOMAIN",
  "clientId": "YOUR_AUTH0_CLIENT_ID"
}
```


Estas variables permiten que su aplicación Angular se identifique como una parte autorizada para interactuar con el servidor de autenticación Auth0 para llevar a cabo el proceso de autenticación.

Ahora debemos usar estas variables en la aplicación Angular para eso vamos a utilizar el environment de Angular.

El environment debería verse así:

```javascript
import { domain, clientId } from '../../auth_config.json';

export const environment = {
  production: false,
  auth: {
    domain,
    clientId,
    redirectUri: window.location.origin,
  },
};
```


Para poder importar archivos JSON dentro de Angular, tenemos que establecer "resolveJsonModule": true en nuestro tsconfig.json


Con estos pasos realizados se ha completado la configuración de un servicio de autenticación que esta listo para ser consumido por la aplicación de Angular


###**3. Configuración del Auth0 Angular SDK**

Ejecute el siguiente comando:


```properties
ng add @auth0/auth0-angular
```


El nuevo Auth0 Angular SDK brinda varios métodos, variables y tipos que ayudan a integrar Auth0 con una aplicación de Angular de una manera más sencilla, este SDK incluye un módulo de autenticación y un servicio.


#### Implementar módulo de autenticación 


Importar AuthModule y environment en el AppModule y luego inicializarlo en los imports.

```javascript
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';

import { AuthModule } from '@auth0/auth0-angular';
import { environment as env } from '../environments/environment';
import { HttpClientModule } from '@angular/common/http';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    HttpClientModule,
    AuthModule.forRoot({
      ...env.auth,
    }),
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }


```


###**4. Autenticar usuario**


Auth0 Angular SDK proporciona métodos para activar eventos de autenticación dentro de los componentes Angular: inicio de sesión, cierre de sesión y registro etc.


####Creando componentes

Vamos a necesitar algunos componentes de Angular para permitirle a usuario iniciar y cerrar la sesión

1. Pagina de inicio
2. Botón para iniciar sesión
3. Botón para cerrar la sesión
4. Component para manejar que Botón mostrar si el de inicio o cierre de sesión.


Con los siguientes comando los podemos crear


```properties
ng g c pages/home
ng g c components/login-button
ng g c components/logout-button
ng g c components/authentication-button
``` 

El component home únicamente lo utilizaremos para mostrar  los botones según sea el caso 

Nuestro archivo de rutas debería verse así:


```javascript
import { HomeComponent } from './pages/home/home.component';
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';

const routes: Routes = [
  {
    path:'',
    component: HomeComponent
  }
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }

```


Ahora el login-button.component.ts  

```javascript
import { Component, OnInit } from '@angular/core';
import { AuthService } from '@auth0/auth0-angular';

@Component({
  selector: 'app-login-button',
  templateUrl: './login-button.component.html',
  styleUrls: ['./login-button.component.scss']
})
export class LoginButtonComponent implements OnInit {

  constructor(public auth: AuthService) {}


  ngOnInit(): void {
  }

  loginWithRedirect(): void {
    this.auth.loginWithRedirect();
  }

}
```


Y el html

```html
<button (click)="loginWithRedirect()">
  Log in
</button>
```


Ahora seguimos con el botón para cerrar la sesión

logout-button.component.ts


```javascript
import { DOCUMENT } from '@angular/common';
import { Component, Inject, OnInit } from '@angular/core';
import { AuthService } from '@auth0/auth0-angular';

@Component({
  selector: 'app-logout-button',
  templateUrl: './logout-button.component.html',
  styleUrls: ['./logout-button.component.scss']
})
export class LogoutButtonComponent implements OnInit {

  constructor(
    public auth: AuthService,
    @Inject(DOCUMENT) private doc: Document
  ) { }

  ngOnInit(): void {
  }

  logout(): void {
    this.auth.logout({ returnTo: this.doc.location.origin });
  }

}
```


Y el html

```html
<button (click)="logout()">
  Log out
</button>
```


Se agrega la propiedad **returnTo** al objeto de configuración para especificar la URL a la que Auth0 debe redirigir a sus usuarios después de cerrar la sesión. En este momento, está trabajando localmente y las "URL de cierre de sesión permitidas" de su aplicación Auth0 apuntan a http://localhost:4200, estas url las configuramos previamente.

Sin embargo, si tuviera que implementar su aplicación Angular en producción , debe agregar la URL de cierre de sesión de producción a la lista "URL de cierre de sesión permitidas.


Otro punto importante es que los componentes de Angular no tiene acceso al objeto **document**, pero se puede inyectar con el @Inject(DOCUMENT)

Luego tenemos que envolver LoginButtonComponent y LogoutButtonComponent en un solo componente que tiene lógica para decidir qué botón renderizar dependiendo del estado de autenticación del usuario.
 
authentication-button.component.ts


```javascript
import { Component, OnInit } from '@angular/core';
import { AuthService } from '@auth0/auth0-angular';

@Component({
  selector: 'app-authentication-button',
  templateUrl: './authentication-button.component.html',
  styleUrls: ['./authentication-button.component.scss']
})
export class AuthenticationButtonComponent implements OnInit {

  constructor(public auth: AuthService) {}

  ngOnInit(): void {
  }

}
```

Y su html

```html
<app-login-button *ngIf="(auth.isAuthenticated$ | async) === false">
</app-login-button>

<app-logout-button *ngIf="auth.isAuthenticated$ | async">
</app-logout-button>
```

Auth0 expone un observable "isAuthenticated$" que emite un valor booleano. Cuando el usuario se ha autenticado el valor es true y cuando no es false.


Y por último debemos agregar el app-authentication-button a nuestro home-component

```html
<app-authentication-button></app-authentication-button>
```

Si haz llegado hasta aquí tu implementación básica esta lista y ya puedes correr la aplicación de Angular y probarla.


```properties
ng serve
```

Cuando hagas clic en el botón "Log In" serás redirigido a la página de acceso universal de Auth0

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9wv7b2oi9w6h19qv2ib6.png)
 

La primera vez que inicies te solicitara que autorices la aplicación.


![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/49cwhudv0qfdwydls6ia.png)


Si iniciaste sesión correctamente deberías de ver el botón de cierre de sesión.


![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5si5qogrno6huvt4l9qk.png)


Cuando termina de iniciar sesión y Auth0 lo redirige a su aplicación Angular, la interfaz de usuario tiene una pantalla en blanco parpadeando.

La interfaz de usuario parpadea porque su aplicación Angular está cargando sus servicios. Mientras se carga, Angular no sabe si Auth0 ya ha autenticado al usuario. Su aplicación conocerá el estado de autenticación del usuario después de que se cargue Auth0 Angular SDK.

Para arreglar eso vamos a validar la sesión en el AppComponent utilizando el observable "isLoading$" que provee el AuthService.

El app.component.ts quedaría así:

```javascript
import { Component } from '@angular/core';
import { AuthService } from '@auth0/auth0-angular';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent {
  title = 'angular-login-auth0';

  constructor(public auth: AuthService) {}
}
```


Y el html


```html
<div *ngIf="auth.isLoading$ | async; else loaded">
  <p>Cargando...</p>
</div>


<ng-template #loaded>
  <router-outlet></router-outlet>
</ng-template>
```


Aquí seria adecuado implementar un componente de "carga" mientras se cargan los servicios.


###**5. Recuperar el perfil del usuario**

Después de que el usuario inicia sesión correctamente, Auth0 envía un token de identificación a su aplicación Angular.


Auth0 utiliza tokens de identificación en la autenticación basada en token para almacenar en caché la información del perfil de usuario y proporcionarla a una aplicación cliente.


Puede utilizar los datos del token de ID para personalizar la interfaz de usuario de su aplicación de Angular. El Auth0 Angular SDK decodifica el token de ID y emite sus datos a través del Observable. Parte de la información del token de ID incluye el nombre, el nickname, la imagen y el correo electrónico del usuario que inició sesión.

Creemos un componente para el perfil 

```properties
ng g c pages/profile
```


El profile.component.ts quedaría de la siguiente manera


```javascript
 import { Component, OnInit } from '@angular/core';
import { AuthService } from '@auth0/auth0-angular';

@Component({
  selector: 'app-profile',
  templateUrl: './profile.component.html',
  styleUrls: ['./profile.component.scss']
})
export class ProfileComponent implements OnInit {

  public profileJson: string = "";
  constructor(public auth: AuthService) {

  }

  ngOnInit(): void {
    this.auth.user$
    .subscribe((profile) => {
      this.profileJson = JSON.stringify(profile, null, 2)
    });
  }

}
```

Y en el html


```html
<pre>{{profileJson}}</pre>
```

Y ahora agregamos una nueva ruta en el app-routing.module.ts

```javascript
import { ProfileComponent } from './pages/profile/profile.component';
import { HomeComponent } from './pages/home/home.component';
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';

const routes: Routes = [
  {
    path:'',
    component: HomeComponent
  },
  {
    path:'profile',
    component: ProfileComponent
  }
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }
```


Cuando naveguemos a la ruta http://localhost:4200/profile
podremos ver la información del usuario.



###**6. Protección de rutas**


Auth0 Angular SDK expone un AuthGuard que puede usar para proteger rutas.


Para requerir que el usuario inicie sesión es tan fácil como agregar la propiedad **canActivate** a la ruta que queremos proteger y agregar el AuthGuard

Importemos el AuthGuard en el app-routing.module.ts


```javascript
import { ProfileComponent } from './pages/profile/profile.component';
import { HomeComponent } from './pages/home/home.component';
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { AuthGuard } from '@auth0/auth0-angular';

const routes: Routes = [
  {
    path:'',
    component: HomeComponent
  },
  {
    path:'profile',
    component: ProfileComponent,
    canActivate: [AuthGuard],
  }
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }

```


###Extra

Si fue curioso pudo notar que cuando ha iniciado sesión con acceso social (Google) y refresca la página la sesión se pierde esto se debe a que las claves de desarrollador Auth0 se están utilizando en lugar de sus propias credenciales para una conexión social.

En la sección de conexiones sociales del panel de Auth0 podrá configurar sus propias credenciales para resolver este problema. Las claves de desarrollo de Auth0 están diseñadas para pruebas y no se recomiendan para entornos de producción.

Otra solución es usar [Refresh Token Rotation](https://auth0.com/docs/tokens/refresh-tokens/refresh-token-rotation) y establecer cacheLocation"localstorage" al inicializar el Auth0 Angular SDK.


```javascript
    AuthModule.forRoot({
      ...env.auth,
      cacheLocation:'localstorage'
    })
```



El repositorio con el código de este tutorial lo podrá encontrar [aquí](https://github.com/ricardochl/angular-login-auth0)


###7. Conclusión

Hemos implementado la autenticación de usuario en Angular, obtener la información del usuario que inicio sesión y también controlar a que rutas pueden acceder los usuarios.

Auth0 es una poderosa solución que nos permite agregar los servicios de Autenticación a nuestras aplicaciones de una manera sencilla haciendo la mayor parte del trabajo por nosotros.

Déjame saber en los comentarios que te pareció este tutorial. 

Gracias por leer está publicación.