Photo by seabass creatives on Unsplash

Angular login for Drupal 8

Simple configurations to accomplish a secure and scalable front end, with all the benefits of a single page application. 

To understand the login from Angular into Drupal 8, I recommend you to read the logic behind the project, it will help you to get all the ideas clear, at least for understand what I want to do and why. Also, there are some configurations in Drupal that I detail in the post SetUp Drupal for web services Integration

Check the Git Project!

What I want to do here is get the token and save it in a local storage. I will use it later for access to forbidden content in Drupal, or for "prove" to angular that I have permissions to access a route. 

$ cd /angdru/src/app
$ tree .
├── app-routing.module.ts
├── app.component.css
├── app.component.html
├── app.component.spec.ts
├── app.component.ts
├── app.module.ts
├── interceptor
│   └── request.interceptor.ts
├── services
│   ├── auth.service.ts
│   ├── guard.service.ts
│   ├── handle-error.service.ts
│   ├── login.service.ts
│   ├── refresh-token.service.ts
│   └── userlist.service.ts
├── token.ts
├── user-list.ts
├── userlist
│   ├── userlist.component.css
│   ├── userlist.component.html
│   └── userlist.component.ts
└── userlogin
    ├── userlogin.component.css
    ├── userlogin.component.html
    └── userlogin.component.ts

I have one module, one router, two classes (just need one), six services, one interceptor and two components. 

A faster explanation of what is doing all these files: The router is activating the Guards services, the app.component is the main component, we all know that.

  • The module is the responsible to bootstrap everything my services, components and external modules. 
  • The interceptor is the responsible to add to the header the token and to handle error responses from Drupal
  • The Authentication service validates my token and he says it to the guards. 
  • The handling error is the responsible for messages like “Invalid password”. 
  • The login service sends the post request with the credential and returns the token into the local storage. 
  • User list service is a simple get method into a route. 
  • The components here are managing the data, either to show or hide information. 

Let’s focus on the login component and how it stores the data. 

First the template, which Is basically a form that gets the name and the password with a pair of inputs, and sends them to the onSubmit function that is in our class. 

User login template:

<div class="container">
    <form (ngSubmit)="onSubmit(name.value, pass.value); name.value=''; pass.value=''" #loginForm="ngForm">
	    <div class="form-group">
	        <label for="name">Name</label>
	        <input type="text" class="form-control" id="name"
	                         required name="name" #name>
	    <div class="form-group">
	        <label for="name">Password</label>
	        <input type="password" class="form-control" id="pass" required name="pass" #pass>
	      <button type="submit" class="btn btn-success">Submit</button>

The onSubmit function from the login component, get the two values and send them to the service, for that remember to import the login service and declare it in the constructor. It also subscribes to the data, if there is something, send us to the next page, or to the error, if something when wrong. 

    onSubmit(name: string, pass: string): void { 
    	name = name.trim();
    	if (!name) { return; }
  		let user: any = { name, pass };
  		this.LoginService.login(, user.pass)
          data => {this.router.navigate (['/']);},         
          error => this.errorMsg = error

In the login service, first declare all the variables that Drupal wants by default, like the URL, the grant_type, and the client. Then, we declare in the constructor, the httpClient and the handle error service, which is the responsible for sending the message “invalid password”. Remember what we saw about Postman and Drupal.

  login (user, pass): Observable<Token> {  	
  	  const url = `${this.mainUrl}oauth/token`;  
  	  let body= new FormData();  	  
  	  body.append("grant_type", this.grant_type);
  	  body.append("client_id", this.client_id);
  	  body.append("client_secret", this.client_secret);
  	  body.append("username", user);
  	  body.append("password", pass);  	  
      return, body)      
      			.map((token: Token) => {      		              
      				localStorage.setItem('token', JSON.stringify(token.access_token));
              localStorage.setItem('refresh_token', JSON.stringify(token.refresh_token));
              return token.access_token      				

It’s important to highlight that we are sending a FormData() because that is what Drupal wants, it won't receive a json. Also, the local storage is saving the token and the refresh token, we will use them later. In the end, we send the error to the handle error service. 

The logout is easy, we can create a simple function for remove the local storage item, the token and the refresh token, and include a router.navigate to the /login or where ever you want after a user logout from your app. 

logout() {
    this.router.navigate (['/login']);

Simple? yes!. Are we validating the data? No?. The only thing we did here was send a FormData and expect some data in response to the redirect to the next page. How are we going to “protect” that data, with Guards in Angular But that is not all, we need to protect that data also from the server and send the token to the server and it will show us the data.