Skip to content

Implemented facebook login auth feature #301

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
{
"window.zoomLevel": -1,
"files.autoSave": "afterDelay",
"window.zoomLevel": 1,
"files.autoSave": "off",
"git.enableSmartCommit": true,
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
}
}
}
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ Check out projects built with the help of this open source app. Feel free to add
- Get `Google_clientID` and `Google_clientSecret` by following [official OAuth tutorial](https://developers.google.com/identity/sign-in/web/sign-in#before_you_begin).

Important: For Google OAuth app, callback URL is: http://localhost:8000/oauth2callback <br/>
Important: For Facebook OAuth app, callback URL is: http://localhost:8000/auth/facebook/callback <br/>
Important: You have to enable Google+ API in your Google Cloud Platform account.

- Specify your own secret key for Express session `SESSION_SECRET`: https://github.com/expressjs/session#secret
Expand All @@ -69,6 +70,10 @@ To use all features and third-party integrations (such as Stripe, Google OAuth,
Google_clientID="xxxxxx"
Google_clientSecret="xxxxxx"

# Used in server/facebook.js
FACEBOOK_CLIENT_ID="xxxxxxxxxx"
FACEBOOK_CLIENT_SECRET="xxxxxxxx"

# Used in server/aws.js
Amazon_accessKeyId="xxxxxx"
Amazon_secretAccessKey="xxxxxx"
Expand Down
2 changes: 1 addition & 1 deletion lib/api/getRootUrl.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
export default function getRootUrl() {
const port = process.env.PORT || 8000;
const dev = process.env.NODE_ENV !== 'production';
const ROOT_URL = dev ? `http://localhost:${port}` : 'https://builderbook.org';
const ROOT_URL = dev ? `http://localhost:${port}` : 'https://ancient-reaches-14182.herokuapp.com';

return ROOT_URL;
}
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
"next": "9.1.6",
"nprogress": "0.2.0",
"passport": "0.4.1",
"passport-facebook": "^3.0.0",
"passport-google-oauth": "2.0.0",
"prop-types": "15.7.2",
"qs": "6.9.1",
Expand Down
12 changes: 12 additions & 0 deletions pages/public/login.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,18 @@ function Login({ router }) {
<p style={{ margin: '45px auto', fontSize: '44px', fontWeight: '400' }}>Log in</p>
<p>You’ll be logged in for 14 days unless you log out manually.</p>
<br />
<Button
variant="contained"
style={{...styleLoginButton,backgroundColor:"darkblue",marginRight:"10px",color:"white"}}
href={`/auth/facebook?redirectUrl=${redirectUrl}`}
>
<img
src="/favicon-16x16.png"
alt="Log in with Facebook"
style={{ marginRight: '10px'}}
/>
Log in with Facebook
</Button>
<Button
variant="contained"
style={styleLoginButton}
Expand Down
Binary file added public/favicon-16x16.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 3 additions & 1 deletion server/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const routesWithSlug = require('./routesWithSlug');
const routesWithCache = require('./routesWithCache');
const sitemapAndRobots = require('./sitemapAndRobots');

const authFace = require('./facebook');
const auth = require('./google');
const { setupGithub } = require('./github');
const api = require('./api');
Expand All @@ -20,7 +21,7 @@ require('dotenv').config();

const dev = process.env.NODE_ENV !== 'production';
const port = process.env.PORT || 8000;
const ROOT_URL = dev ? `http://localhost:${port}` : 'https://builderbook.org';
const ROOT_URL = dev ? `http://localhost:${port}` : 'https://ancient-reaches-14182.herokuapp.com';

const MONGO_URL = dev ? process.env.MONGO_URL_TEST : process.env.MONGO_URL;

Expand Down Expand Up @@ -92,6 +93,7 @@ app.prepare().then(async () => {
await insertTemplates();

auth({ server, ROOT_URL });
authFace({ server, ROOT_URL });
setupGithub({ server });
api(server);

Expand Down
99 changes: 99 additions & 0 deletions server/facebook.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
const passport = require('passport');
const strategy = require("passport-facebook");
const User = require('./models/User');
const FacebookStrategy = strategy.Strategy;

function authFace({ ROOT_URL, server }) {
const verify = async (accessToken, refreshToken, profile, verified) => {
const { first_name, last_name } = profile._json;
let email;
let avatarUrl;
if (profile.emails) {
email = profile.emails[0].value;
}

if (profile.photos && profile.photos.length > 0) {
avatarUrl = profile.photos[0].value;
}

try {
const user = await User.signInOrSignUp({
email,
firstName: first_name,
lastName: last_name,
googleId: profile.id,
googleToken: { accessToken, refreshToken },
displayName: profile.displayName,
avatarUrl,
});
verified(null, user);
} catch (err) {
verified(err);
console.log(err); // eslint-disable-line
}
};
passport.use(
new FacebookStrategy(
{
clientID: process.env.FACEBOOK_CLIENT_ID,
clientSecret: process.env.FACEBOOK_CLIENT_SECRET,
callbackURL: `${ROOT_URL}/auth/facebook/callback`,
profileFields: ["id", "name","emails","displayName","profileUrl",'picture.type(large)']
},
verify,
),
);

passport.serializeUser((user, done) => {
done(null, user.id);
});

passport.deserializeUser((id, done) => {
User.findById(id, User.publicFields(), (err, user) => {
done(err, user);
// eslint-disable-next-line no-console
console.log('deserializeUser', id);
});
});

server.use(passport.initialize());
server.use(passport.session());

server.get('/auth/facebook', (req, res, next) => {
const options = {
scope: ['email'],
};

if (req.query && req.query.redirectUrl && req.query.redirectUrl.startsWith('/')) {
req.session.finalUrl = req.query.redirectUrl;
} else {
req.session.finalUrl = null;
}

passport.authenticate('facebook', options)(req, res, next)
}
);

server.get(
'/auth/facebook/callback',
passport.authenticate('facebook', {
failureRedirect: '/login',
}),
(req, res) => {
if (req.user && req.user.isAdmin) {
res.redirect('/admin');
} else if (req.session.finalUrl) {
res.redirect(req.session.finalUrl);
} else {
res.redirect('/my-books');
}
},
);

server.get('/logout', (req, res) => {
req.logout();
res.redirect('/login');
});
}

module.exports = authFace;
Loading