Implementing oAuth authentication with Electron

We have checked how we can authenticate an application with the Facebook SDK. There are some other situations where we have to implement oAuth authentication, which is not a simple task. With oAuth, the authentication process will be happening at a remote URL and will be redirected to the client domain when the authentication is successful. So we need to handle redirections. Usually, it's easy with a normal web application as the server will simply redirect to the domain. But with Electron, we don't have any domain running from the local file and the server does not have any access to our local HTML file embedded inside the Electron shell. So, it's a challenge to handle this with Electron. Let's look at how we can implement oAuth authentication with Electron. As an example, let's try to log in to the GitHub API with Electron. This part is not included in the sample application but we need to have a clear idea about this type of authentication with Electron as the procedure is a little bit different from the traditional web application.

The initial step is to configure the GitHub application's credentials:

 var options = { 
client_id: 'your_client_id',
client_secret: 'your_client_secret',
// Scopes limit access for OAuth tokens.
scopes: ["user:email", "notifications"]
};

We need to open the resource manager's (in this case, GitHub.com) authentication page, which enables the user to authenticate with their system. Add the following to your page:

var authWindow = new BrowserWindow({ width: 800, height: 600, show: false, 'node-integration': false }); 
var githubUrl = 'https://github.com/login/oauth/authorize?';
var authUrl = githubUrl + 'client_id=' + options.client_id + '&scope=' + options.scopes;
authWindow.loadURL(authUrl);
authWindow.show();

Once you are logged into the website, the server will redirect the page into your domain. In this case, we need to handle the redirection manually as we are running from the local filesystem. Electron emits two events when the page is about to redirect:

authWindow.webContents.on('will-navigate', function (event, url) { 
handleCallback(url);
});

authWindow.webContents.on('did-get-redirect-request', function (event, oldUrl, newUrl) {
handleCallback(newUrl);
});

The remote server will pass the authentication code along with the redirected URL. You can also get the error messages with the URL if any error occurs. We need to extract the authentication code from the URL as follows:

function handleCallback (url) { 
var raw_code = /code=([^&]*)/.exec(url) || null;
var code = (raw_code && raw_code.length > 1) ? raw_code[1] : null;
var error = /?error=(.+)$/.exec(url);

if (code || error) {
// Close the browser if code found or error
authWindow.destroy();
}

// If there is a code, proceed to get token from github
if (code) {
self.requestGithubToken(options, code);
} else if (error) {
alert('Oops! Something went wrong and we couldn't' +
'log you in using Github. Please try again.');
}
}

Release the auth window object on close:

authWindow.on('close', function() { 
authWindow = null;
}, false);

Once the user is authenticated, we need to request the authentication token that should be attached with each API request sent to the server. Once the token is received, save it in a shared storage where both the main process and the renderer process have access like local storage:

function requestGithubToken(options, code) { 
fetch('https://github.com/login/oauth/access_token', {
method: 'POST'
body: {
client_id: options.client_id,
client_secret: options.client_secret,
code: code,
}
})
.then(function (response) {
if (response && response.ok) {
window.localStorage.setItem('githubtoken', response.body.access_token);
}
});
}

If everything is implemented correctly, you can now start accessing the GitHub content. This is almost the same as any oAuth authentication provider. Even with Facebook, you can follow these steps. But Facebook provides a wrapper for this through the Facebook SDK. For our Angular application, the same code can be rewritten as an Angular service as follows:

import { Injectable } from '@angular/core'; 
import { Http, Headers } from '@angular/http';
import { Store } from '@ngrx/store';
import { AppState } from './../store/appState.store';
import { AUTH_ACTION_TYPES } from './../store/auth.store';
import { remote, BrowserWindow } from 'electron'

const options = {
client_id: 'your_client_id',
client_secret: 'your_client_secret',
// Scopes limit access for OAuth tokens.
scopes: ["user:email", "notifications"]
};

Update the authentication service with the following constructor. The browser window should be initialized inside the constructor. This browser window can be used to load the oAuth login page:

 
@Injectable()
export class Authentication {
authWindow: any;
http: Http;

constructor(public store: Store<AppState>, http: Http) {
this.authWindow = new BrowserWindow({ width: 800, height: 600, show: false });
}
}

Add the following method into the service. Build the oAuth page login URL and load it into the BrowserWindow. When you log in successfully, the page will be redirected to the callback URL that you configured in your app. You need to handle it using the will-navigate event handler of the BrowserWindow:

githubHandShake() { 

// Build the OAuth consent page URL
let githubUrl = 'https://github.com/login/oauth/authorize?';
let authUrl = githubUrl + 'client_id=' + options.github.client_id + '&scope=' + options.github.scopes;
this.authWindow.loadUrl(authUrl);
this.authWindow.show();

// Handle the response from GitHub
this.authWindow.webContents.on('will-navigate', (event, url) => {
this.handleGitHubCallback(url);
});

this.authWindow.webContents.on('did-get-redirect-request', (event, oldUrl, newUrl) => {
this.handleGitHubCallback(newUrl);
});

// Reset the authWindow on close
this.authWindow.on('close', function () {
this.authWindow = null;
}, false);
}

Add the following method to your service. This handles your oAuth provider callback. When the login is successful, this method asks for the authentication token which needs to be added to all your requests after the login:

  handleGitHubCallback(url) { 
let raw_code = /code=([^&]*)/.exec(url) || null;
let code = (raw_code && raw_code.length > 1) ? raw_code[1] : null;
let error = /?error=(.+)$/.exec(url);

if (code || error) {
// Close the browser if code found or error
this.authWindow.destroy();
}

// If there is a code, proceed to get token from github
if (code) {
this.requestGithubToken(options.github, code);
} else if (error) {
alert('Oops! Something went wrong and we couldn't' +
'log you in using Github. Please try again.');
}
}

The following code requests the token to GitHub. Add the following code into the service:

 
requestGithubToken(githubOptions, githubCode) {
let creds = 'client_id=' + githubOptions.client_id + '&client_secret=' + githubOptions.client_secret + '&code=' + githubCode;

let headers = new Headers();
headers.append('Accept', 'application/json');

this.http.post('https://github.com/login/oauth/access_token?' + creds, '', { headers: headers })
.subscribe(
response => {
//call the store to update the authToken
let body_object = JSON.parse(response['_body']);
this.requestUserData(body_object.access_token);
},
err => console.log(err),
() => console.log('Authentication Complete')
);

}
requestUserData(token) {

let headers = new Headers();
headers.append('Accept', 'application/json');

this.http.get('https://api.github.com/user?access_token=' + token, { headers: headers })
.subscribe(
response => {
//call local storage
},
err => console.log(err),
() => console.log('Request Complete')
);
}
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.133.112.82