Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

FB/Google client-side login(Ionic) with existing API

My stack is:

  • Ionic 2
  • Java Spring
  • JWT authentication

and I want to implement a Social login button (Facebook, Google etc.) inside my app with the respective cordova plugins, that logs in the user and validates him on my existing custom server-side API and store his/her data. I wasn't able to find any good tutorial on how to do this.

I want my user to be persisted in the database with a random password and be able to login from my app.

I was imagining something along the lines of:

(client-side)

FB.login(function(userDetailsAndToken) {
    myBackendAPI.socialLogin(userDetailsAndToken).then(function(user) {
        //Successfully logged in with Facebook!
        this.user = user;
    }
}

and in the backend (Java Spring):

@PostMapping("/social/account")
public ResponseEntity socialAccount(@Valid @RequestBody FacebookDTO facebookDTO) {
    validateSocialUser(facebookDTO);

    //if user exists return invalid etc.
    Optional<User> existingUser = userRepository.findOneByEmail(facebookDTO.getEmail());
    if (existingUser.isPresent()) {
        return ResponseEntity.badRequest();
    }

    //User doesn't exist. Proceed with login 
    //map from social to my User entity
    User user = socialMapper.toEntity(facebookDTO);

    userService
        .createUser(user.getLogin(), user.getPassword(),
            user.getFirstName(), user.getLastName(),
            user.getEmail().toLowerCase(), user.getImageUrl(),
            user.getLangKey());
    return new ResponseEntity<>(HttpStatus.CREATED);
}

Is this possible and secure? Any good resources/libraries or guidelines on how to achieve that?

like image 314
Alex Arvanitidis Avatar asked Aug 22 '17 20:08

Alex Arvanitidis


1 Answers

Here is a sample demo about working with FB and Google Auth , but i'm not from a Java background so you will be finding only client side solution.

service

let’s implement the logic for the login functionality. Create an oauth.service.ts file in the oauth folder and paste the following code in there:

import { Injectable, Injector } from '@angular/core';
import { FacebookOauthProvider } from './facebook/facebook-oauth.provider';
import { IOathProvider } from './oauth.provider.interface';
import { GoogleOauthProvider } from './google/google-oauth.provider';
import { OAuthToken } from './models/oauth-token.model';
@Injectable()
export class OAuthService {
    private oauthTokenKey = 'oauthToken';
    private injector: Injector;
constructor(injector: Injector) {
        this.injector = injector;
    }
login(source: string): Promise {
        return this.getOAuthService(source).login().then(accessToken => {
            if (!accessToken) {
                return Promise.reject('No access token found');
            }
let oauthToken = {
                accessToken: accessToken,
                source: source
            };
            this.setOAuthToken(oauthToken);
            return oauthToken;
        });
    }
getOAuthService(source?: string): IOathProvider {
        source = source || this.getOAuthToken().source;
        switch (source) {
            case 'facebook':
                return this.injector.get(FacebookOauthProvider);
            case 'google':
                return this.injector.get(GoogleOauthProvider);
            default:
                throw new Error(`Source '${source}' is not valid`);
        }
    }
setOAuthToken(token: OAuthToken) {
        localStorage.setItem(this.oauthTokenKey, JSON.stringify(token));
    }
getOAuthToken(): OAuthToken {
        let token = localStorage.getItem(this.oauthTokenKey);
        return token ? JSON.parse(token) : null;
    }
}

Authentication provider and token interfaces As we have already mentioned, the IOathProvider should include a login() function. Therefore, we should set the following interface that will act as an abstract type/model for the IOathProvider object. Create an oauth.provider.interface.ts file in the oauth folder and include the following lines in it:

export interface IOathProvider {
    login(): Promise;
}

Facebook and Google authentication services

As a next step, we should implement the services for each one of the authentication providers our app has, i.e. FacebookOauthProvider and GoogleOauthProvider.

Install dependencies

Here is when the ng2-cordova-oauth library comes handy. We can install it by executing the command: npm install ng2-cordova-oauth --save

Also, our app relies on the Cordova InAppBrowser plugin. We are going to install it with:

ionic plugin add cordova-plugin-inappbrowser

Do not forget to include cordova-plugin-inappbrowser in your package.json file too, so it can be installed with the rest of the plugins anytime you install your project from scratch.

Implement the Facebook and Google authentication providers

Let’s create the facebook-oauth.provider.ts file under the oauth/facebook/ path. In this file, include the code in the snippet:

 import { Injectable } from '@angular/core';
    import { Http } from '@angular/http';
    import { IOathProvider } from '../oauth.provider.interface';
    import { CordovaOauth } from 'ng2-cordova-oauth/oauth';
    import { Facebook } from 'ng2-cordova-oauth/provider/facebook';
    import { Config } from '../../../config';
    interface ILoginResponse {
        access_token: string;
    }
    @Injectable()
    export class FacebookOauthProvider implements IOathProvider {
        private cordovaOauth: CordovaOauth;
        private http: Http;
        private config: Config;
        private facebook: Facebook;
    constructor(http: Http, config: Config) {
            this.http = http;
            this.config = config;
            this.facebook = new Facebook({ clientId: config.facebook.appId, appScope: config.facebook.scope });
            this.cordovaOauth = new CordovaOauth();
        }
    login(): Promise {
            return this.cordovaOauth.login(this.facebook)
                .then((x: ILoginResponse) => x.access_token);
        }
    }

Similarly, using the CordovaOauth object available by the ng2-cordova-oauth library, we will implement the Google authentication provider with its own login() function. However, here we pass another clientId from Config that corresponds to the application we configured with Google using the Google Developer Console. Therefore, create a google-oauth.provider.ts file and paste the following lines:

import { Injectable } from '@angular/core';
import { IOathProvider } from '../oauth.provider.interface';
import { OAuthProfile } from '../models/oauth-profile.model';
import { CordovaOauth } from 'ng2-cordova-oauth/oauth';
import { Google } from 'ng2-cordova-oauth/provider/google';
import { Config } from '../../../config';
import { Http } from '@angular/http';
interface ILoginResponse {
    access_token: string;
}
@Injectable()
export class GoogleOauthProvider implements IOathProvider {
    private http: Http;
    private config: Config;
    private cordovaOauth: CordovaOauth;
    private google: Google;
constructor(http: Http, config: Config) {
        this.http = http;
        this.config = config;
        this.google = new Google({ clientId: config.google.appId, appScope: config.google.scope });
        this.cordovaOauth = new CordovaOauth();
    }
login(): Promise {
        return this.cordovaOauth.login(this.google).then((x: ILoginResponse) => x.access_token);
    }
getProfile(accessToken: string): Promise {
        let query = `access_token=${accessToken}`;
        let url = `${this.config.google.apiUrl}userinfo?${query}`;
return this.http.get(url)
            .map(x => x.json())
            .map(x => {
                let name = x.name.split(' ');
                return {
                    firstName: name[0],
                    lastName: name[1],
                    email: x.email,
                    provider: 'google'
                };
            })
            .toPromise();
    }
}

Full credits to this Article and you can find the Working Code in Github. I haven't covered the whole Tutorial , only the parts (Google and Facebook) of that tutorial .i.e. What plugin we need to install and how to use using the TypeScript , if you need beyond that then you can refer to that tutorial

like image 191
Tummala Krishna Kishore Avatar answered Sep 18 '22 12:09

Tummala Krishna Kishore