Skip to content

Commit

Permalink
feature(socialLogin google):socialLogin using google
Browse files Browse the repository at this point in the history
setup social Login using passport google

[Delivers #167574995]
  • Loading branch information
Adekoreday committed Aug 7, 2019
1 parent 74c3019 commit 3bb0149
Show file tree
Hide file tree
Showing 9 changed files with 160 additions and 72 deletions.
11 changes: 3 additions & 8 deletions server/controllers/Auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,10 @@ class Auth {
* @param {Object} response express response object
* @returns {JSON} JSON object with details of new user
*/
static async facebookSocialLogin(request, response) {
console.log('request', request);
/* const { devicePlatform, userAgent } = getUserAgent(request);
static async socialLogin(request, response) {
const { devicePlatform, userAgent } = getUserAgent(request);
const { ip } = request;
const { givenName, familyName, email } = getSocialUserData(
request,
'facebook'
);
const { givenName, familyName, email } = getSocialUserData(request);
const data = {
firstName: givenName,
lastName: familyName,
Expand All @@ -37,7 +33,6 @@ class Auth {
const user = await createSocialUsers(data);
delete user.password;
serverResponse(response, 200, user);
*/
}
}
export default Auth;
49 changes: 21 additions & 28 deletions server/docs/authors-haven-api.yml
Original file line number Diff line number Diff line change
Expand Up @@ -114,47 +114,38 @@ paths:
content:
application/json:
schema:
"$ref": "#/components/FacebookUserSignUp"
"$ref": "#/components/SocialUserSignUp"
400:
description: Bad request
content:
application/json:
schema:
"$ref": "#/components/schemas/fbserverResponse"
"$ref": "#/components/schemas/SocialserverResponse"

/api/v1/sessions/destroy:
/api/v1/auth/google:
get:
summary: Sign out Route
description: Sign out Route
summary: Route for signing new using google
description: Allow new user to Login using google
responses:
"200":
description: Sign out successful
302:
description: redirect url
/api/v1/auth/google/callback:
get:
summary: redirect url for google login/signup
description: Allow existing users to signup or login
responses:
200:
description: Login successful
content:
application/json:
schema:
"$ref": "#/components/schemas/signoutResponse"
"400":
"$ref": "#/components/SocialUserSignUp"
400:
description: Bad request
content:
application/json:
schema:
"$ref": "#/components/schemas/errorResponse"
"403":
description: Incorrect username or password
content:
application/json:
schema:
"$ref": "#/components/schemas/errorResponse"
"500":
description: Server Error
content:
application/json:
schema:
"$ref": "#/components/schemas/serverResponse"
security:
- BearerAuth: []


"$ref": "#/components/schemas/SocialserverResponse"
components:
securitySchemes:
BearerAuth:
Expand Down Expand Up @@ -187,7 +178,7 @@ components:
confirmPassword:
type: string
example: incorrect
FacebookUserSignUp:
SocialUserSignUp:
type: object
required:
- firstName
Expand Down Expand Up @@ -239,14 +230,16 @@ components:
properties:
error:
type: string
fbserverResponse:
SocialserverResponse:
type: object
properties:
message:
type: string
example: Auth failed
signoutResponse:
type: object
properties:
message:
type: string


21 changes: 11 additions & 10 deletions server/helpers/getSocialUserData.js
Original file line number Diff line number Diff line change
@@ -1,31 +1,32 @@
/**
* @name facebookData
* @name getuserData
* @async
* @param {Object} request express request object
* @returns {Object} facebookUserData with details of new user
* @returns {Object} facebook or Google data with details of new user
*/
const facebookData = (request) => {
const getuserData = (request) => {
const { email } = request.user._json;
const { givenName, familyName } = request.user.name;
const facebookUserData = {
const data = {
email,
givenName,
familyName
};
return facebookUserData;
return data;
};
/**
* @name getSocialUserData
* @async
* @param {Object} request express request object
* @param {string} provider provider type of social media authenticator
* @returns {Object} userData with details of new user
*/
const getSocialUserData = (request, provider) => {
const getSocialUserData = (request) => {
let userData;
switch (provider) {
case 'facebook': {
userData = facebookData(request);
const { path } = request.route;
switch (path) {
case '/facebook/callback':
case '/google/callback': {
userData = getuserData(request);
break;
}
default:
Expand Down
16 changes: 16 additions & 0 deletions server/helpers/google.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import passport from 'passport';
import { Strategy as GoogleStrategy } from 'passport-google-oauth20';
import passportCallback from '../middlewares/passportCallback';

export default () => {
passport.use(
new GoogleStrategy(
{
clientID: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
callbackURL: process.env.GOOGLE_REDIRECT_URL
},
passportCallback
)
);
};
4 changes: 2 additions & 2 deletions server/routes/auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ auth.get(
'/facebook/callback',
passport.authenticate('facebook', { session: false, failureRedirect: '/' }),
PassportError.passportErrors,
Auth.facebookSocialLogin
Auth.socialLogin
);
auth.get(
'/google',
Expand All @@ -22,6 +22,6 @@ auth.get(
auth.get(
'/google/callback',
passport.authenticate('google', { failureRedirect: '/' }),
Auth.facebookSocialLogin
Auth.socialLogin
);
export default auth;
35 changes: 34 additions & 1 deletion test/auth/__mocks_/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
const request = {
route: {
path: '/facebook/callback'
},
user: {
name: {
givenName: 'Raambo',
Expand All @@ -14,10 +17,40 @@ const request = {
},
ip: '168.212.226.204'
};

const request2 = {
route: {
path: '/google/callback'
},
user: {
name: {
givenName: 'Team',
familyName: 'RamboG'
},
_json: {
email: 'dev@gmail.com'
}
},
headers: {
'user-agent': `Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_2)
AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36`
},
ip: '168.212.226.204'
};
const users = [
{
dataValues: { id: 3 }
}
];
const mockrequest = {
route: {
path: ''
}
};
const profile = {
error: 'Auth failed'
};

export { request, users };
export {
request, request2, users, mockrequest, profile
};
52 changes: 31 additions & 21 deletions test/auth/facebookLogin.test.js → test/auth/facebook.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,40 +2,49 @@ import chai from 'chai';
import chaiHttp from 'chai-http';
import sinon from 'sinon';
import nock from 'nock';
import passport from 'passport';
import Passport from '../../server/helpers/passport';
import PassportError from '../../server/middlewares/passportError';
import getSocialUserData from '../../server/helpers/getSocialUserData';
import facebook from '../../server/helpers/facebook';
import Auth from '../../server/controllers/Auth';
import models from '../../server/database/models/index';
import { request, users } from './__mocks_';
import passportCallback from '../../server/middlewares/passportCallback';
import {
request, users, mockrequest, profile
} from './__mocks_';

const { expect } = chai;
chai.use(chaiHttp);
let sinons;
const { User, Session } = models;
let serialize, deserialize;
describe('facebook login test', () => {
before(() => {
sinons = sinon.stub(User, 'findOne').returns(false);
serialize = sinon.stub(passport, 'serializeUser').yields({}, () => {});
deserialize = sinon.stub(passport, 'deserializeUser').yields({}, () => {});
});

after(() => {
sinons.restore();
deserialize.restore();
serialize.restore();
});

it('it should test route nock off the http request to fb', async (done) => {
it('nock off the http request to facebook', async () => {
nock('https://wwww.facebook.com')
.get('/api/v1/auth/facebook/callback')
.reply(200, {
hello: 'facebook'
});
done();
});

it('it mocks passport app', async () => {
it('mocks passport app', async () => {
const app = { use() {} };
await Passport(app);
});
it('it mock passport Error check on pass', async () => {
it('mock passport Error check on pass', async () => {
const res = { status() {}, json() {} };
const status = sinon.stub(res, 'status').returnsThis();
const json = sinon.stub(res, 'json').returnsThis();
Expand All @@ -46,40 +55,41 @@ describe('facebook login test', () => {
sinon.assert.calledOnce(json);
});

it('it mock passport Error check on pass', async () => {
const res = { status() {}, json() {} };
const status = sinon.stub(res, 'status').returnsThis();
const json = sinon.stub(res, 'json').returnsThis();
const Callbackrequest = sinon.stub();
const Callbacknext = sinon.stub();
PassportError.passportErrors(true, Callbackrequest, res, Callbacknext);
sinon.assert.calledOnce(status);
sinon.assert.calledOnce(json);
});

it('it mock passport Error check on fail', async () => {
it('mock passport Error check on fail', async () => {
const Callbacknext = sinon.stub();
const Callbackrequest = sinon.stub();
const res = { status() {}, json() {} };
const status = sinon.stub(res, 'status').returnsThis();
const json = sinon.stub(res, 'json').returnsThis();
getSocialUserData(null, '');
getSocialUserData(mockrequest);
PassportError.passportErrors(false, Callbackrequest, res, Callbacknext);
sinon.assert.calledOnce(Callbacknext);
sinon.assert.calledOnce(status);
sinon.assert.calledOnce(json);
});

it('it facebookLoginController', async () => {
it('register a new user sucessfully', async () => {
const res = { status() {}, json() {} };
const status = sinon.stub(res, 'status').returnsThis();
const json = sinon.stub(res, 'json').returnsThis();
const Sessions = sinon.stub(Session, 'create').returns(false);
const findOrCreate = sinon.stub(User, 'findOrCreate').returns(users);
await Auth.facebookSocialLogin(request, res);
await Auth.socialLogin(request, res);
sinon.assert.calledOnce(status);
sinon.assert.calledOnce(json);
Sessions.restore();
findOrCreate.restore();
});
context('when a valid user wants to login using facebook', () => {
it('logs in the user successfully', async () => {
const response = facebook();
expect(response).to.equal(undefined);
});
});
context('when an invalid user want to login with facebook', () => {
it('returns error message', () => {
const result = passportCallback(null, null, profile, (err, next) => next);
expect(result).to.be.instanceOf(Object);
expect(result.error).to.be.equal('Auth failed');
});
});
});
39 changes: 39 additions & 0 deletions test/auth/google.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import chai from 'chai';
import sinon from 'sinon';
import google from '../../server/helpers/google';
import Auth from '../../server/controllers/Auth';
import models from '../../server/database/models/index';
import passportCallback from '../../server/middlewares/passportCallback';
import { request2, users, profile } from './__mocks_';

const { expect } = chai;
const { User, Session } = models;
describe('google login test', () => {
context('when a valid user want to login with google', () => {
it('logs in such user successfully', async () => {
const res = { status() {}, json() {} };
const status = sinon.stub(res, 'status').returnsThis();
const json = sinon.stub(res, 'json').returnsThis();
const Sessions = sinon.stub(Session, 'create').returns(false);
const findOrCreate = sinon.stub(User, 'findOrCreate').returns(users);
await Auth.socialLogin(request2, res);
sinon.assert.calledOnce(status);
sinon.assert.calledOnce(json);
Sessions.restore();
findOrCreate.restore();
});
});
context('when an invalid user want to login with google', () => {
it('returns error message', () => {
const result = passportCallback(null, null, profile, (err, next) => next);
expect(result).to.be.instanceOf(Object);
expect(result.error).to.be.equal('Auth failed');
});
});
context('when a valid user wants to login using google', () => {
it('logs in the user successfully', async () => {
const response = google();
expect(response).to.equal(undefined);
});
});
});
Loading

0 comments on commit 3bb0149

Please sign in to comment.