Skip to content

Instantly share code, notes, and snippets.

@jermsam
Created May 15, 2019 15:23
Show Gist options
  • Save jermsam/226846bcab710a678e0ea513492787b6 to your computer and use it in GitHub Desktop.
Save jermsam/226846bcab710a678e0ea513492787b6 to your computer and use it in GitHub Desktop.
my aouth flow as of now
const authentication = require('@feathersjs/authentication');
const jwt = require('@feathersjs/authentication-jwt');
const oauth2 = require('@feathersjs/authentication-oauth2');
const GoogleStrategy = require('passport-google-oauth20');
const EmailFirstOAuth2Verifier = require('./verifier');
// Bring in the oauth-handler
const makeHandler = require('./oauth-handler');
const callbackHook = hook => {
return async (req, res, next) => {
try {
const { data } = await hook.app.authenticate('jwt')(req, res);
if (data && data.user) req.user = data.user;
next();
} catch (ex) {
next();
}
};
};
module.exports = function(app) {
// Create a handler by passing the `app` object.
const handler = makeHandler(app);
const config = app.get('authentication');
const successRedirect = `${config.redirectLink}/verifysocial`;
// Set up authentication with the secret
app.configure(authentication(config));
app.configure(jwt());
app.configure(
oauth2(
Object.assign(
{
name: 'google',
Strategy: GoogleStrategy,
clientID: config.google.clientID,
clientSecret: config.google.clientSecret,
Verifier: EmailFirstOAuth2Verifier,
// Provide the handler to the Google auth setup.
// The successRedirect should point to the handle-oauth-login.html hosted on the web server.
handler: handler(successRedirect),
emailField: 'email',
callbackHook,
},
config.google
)
)
);
app.service('authentication').hooks({
before: {
create: [authentication.hooks.authenticate(config.strategies)],
remove: [authentication.hooks.authenticate('jwt')],
},
});
};
module.exports = function (app) {
return function (url) {
const config = app.get('authentication');
const options = {
jwt: config.jwt,
secret: config.secret
};
return function (req, res, next) {
if (req.feathers && req.feathers.payload) {
app.passport.createJWT(req.feathers.payload, options).then(token => {
res.redirect(`${url}?token=${token}`);
})
.catch(error => {
next(error);
});
}
};
};
};
const Debug = require('debug');
const { Verifier } = require('@feathersjs/authentication-oauth2');
const debug = Debug('feathers-authentication-emailfirstoauth2:verify');
class EmailFirstOAuth2Verifier extends Verifier {
constructor(app, options = {}) {
options.emailField = options.emailField || 'email';
super(app, options);
}
verify(req, accessToken, refreshToken, profile, done) {
// console.log(profile);
debug('Checking credentials');
const options = this.options;
const query = {
$or: [
{ [options.idField]: profile.id },
{ [options.emailField]: { $in: profile.emails.map(emailObj => emailObj.value) } },
],
$limit: 1,
};
const data = { profile, accessToken, refreshToken };
let existing;
// Check request object for an existing entity
if (req && req[options.entity]) {
existing = req[options.entity];
}
// Check the request that came from a hook for an existing entity
if (!existing && req && req.params && req.params[options.entity]) {
existing = req.params[options.entity];
}
// If there is already an entity on the request object (ie. they are
// already authenticated) attach the profile to the existing entity
// because they are likely "linking" social accounts/profiles.
if (existing) {
return this._updateEntity(existing, data)
.then(entity => done(null, entity))
.catch(error => (error ? done(error) : done(null, error)));
}
// Find or create the user since they could have signed up via facebook.
this.service
.find({ query })
.then(this._normalizeResult)
.then(entity => (entity ? this._updateEntity(entity, data) : this._createEntity(data)))
.then(entity => {
const id = entity[this.service.id];
const payload = { [`${this.options.entity}Id`]: id };
done(null, entity, payload);
})
.catch(error => (error ? done(error) : done(null, error)));
}
}
module.exports = EmailFirstOAuth2Verifier;
import React from 'react';
import { Grid, Header, Image,Loader,Divider } from 'semantic-ui-react';
import Layout from './layout';
import VerifyForm from './forms/VerifyForm';
import { sendToken } from '../feathers';
import { Router } from '../routes';
const INNITIAL_STATE = {
email: '',
isVerified: false,
isLoading:false
};
class Page extends React.PureComponent {
state = INNITIAL_STATE;
componentWillMount() {
const { authUser } = this.props;
if (authUser) {
Router.push(`/dashboard?userId=${authUser.id}`);
}
}
componentDidMount() {
this._isMounted = true;
this.sendToSignIn();
}
componentDidUpdate(prevProps, prevState) {
const { email, token } = this.props;
const { isVerified } = this.state;
if (
prevProps.token !== token ||
prevProps.email !== email ||
prevState.isVerified !== isVerified
) {
this.sendToSignIn();
}
}
sendToSignIn = async () => {
const { token } = this.props;
try {
if (token) {
if(this._isMounted){
this.setState({ isLoading:true});
const { email, isVerified } = await sendToken(
'verifySignupLong',
token
);
this.setState({ isVerified });
Router.push(
`/signin?email=${email}&&emailverification=${isVerified}`
);
this.setState({ isLoading:false });
}
}
} catch ({ message }) {
console.log('Error: ', message);
}
};
render() {
const { email } = this.props;
const { isVerified,isLoading } = this.state;
return (
<Layout
desktop={<PageContent {...{ email }} {...{ isVerified }} {...{isLoading}}/>}
mobile={<PageContent {...{ email }} {...{ isVerified }} {...{isLoading}}/>}
/>
);
}
}
Page.getInitialProps = ({ query: { email, token } }) => ({ email, token });
export default Page;
const PageContent = ({ email, isVerified ,isLoading}) => (
<>
{isLoading ?
<Grid
columns={1}
verticalAlign="middle"
textAlign="center"
style={{ minHeight: '100vh' }}
>
<Grid.Column>
<Header
sub
content="redirecting"
subheader="please wait ..."
/>
<Divider section hidden />
<Loader active={isLoading} inline="centered" size="massive" />
</Grid.Column>
</Grid>
:
<Grid textAlign="center" style={{ height: '100%' }} verticalAlign="middle">
<Grid.Column style={{ maxWidth: 450 }} id='top'>
{!isVerified && (
<>
{' '}
<Header as="h2" color="grey" textAlign="center">
<Image src="/static/imgs/chat-logo.png" /> Account Verification
</Header>
<VerifyForm {...{ email }} />
</>
)}
</Grid.Column>
</Grid>
}
</>
);
import React, { Component } from 'react';
import { app } from '../feathers';
import { Router } from '../routes';
async function setJwtTocken(token) {
try {
// remove cause it was for testing purposes
// localStorage.removeItem('feathers-jwt');
return await window.localStorage.setItem('feathers-jwt', token);
} catch (err) {
return {};
}
}
export default class VerifySocialPage extends Component {
state = {
// loading: true
};
_isMounted = false;
componentWillMount() {}
componentDidMount() {
this._isMounted = true;
this.handleVerify();
}
componentWillUnmount() {
this._isMounted = false;
}
handleVerify = async () => {
const { token } = this.props;
try {
// extract userId from jwtToken payload
const { userId } = await app.passport.verifyJWT(token);
// Get our initialized service so that we can register hooks and filters
// Get id and verify token for user with Id
const { verifyToken } = await app.service('users').get(userId);
if (verifyToken) {
// console.log('ver: ', verifyToken);
Router.push(`/verify?id=${userId}&&token=${verifyToken}`);
} else {
await setJwtTocken(token);
await Router.push(`/dashboard?userId=${userId}`);
window.location.reload();
}
} catch ({ message }) {
console.log('Error: ', message);
}
};
render() {
return <div />;
}
}
VerifySocialPage.getInitialProps = ({ query: { token } }) => ({ token });
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment