Custom Auth Login + verify invite token
This commit is contained in:
1 parent
caba8bb338
commit
4ca444addf
9 files changed
+162
-13
No files matched your search
@@ -7,7 +7,7 @@ const sendTeamMemberInvite = function(email, team) {
|
||||
const API_KEY = process.env.SG_APIKEY
|
||||
const token = jwt.sign({ email: email, team: team.slug }, API_KEY, { expiresIn: '7d' })
|
||||
let origin = 'https://teams.advancedalgos.net'
|
||||
const params = '/activate-team-membership?token='
|
||||
const params = '/activate-team-membership/'
|
||||
if (dev){
|
||||
origin = 'http://localhost:3001'
|
||||
}
|
||||
@@ -67,4 +67,21 @@ const sendTeamMemberInvite = function(email, team) {
|
||||
return sendVerify
|
||||
}
|
||||
|
||||
module.exports = { sendTeamMemberInvite }
|
||||
const verifyInviteToken = async function(token) {
|
||||
const API_KEY = process.env.SG_APIKEY
|
||||
let verifiedToken
|
||||
try {
|
||||
verifiedToken = await jwt.verify(token, API_KEY, {maxAge: '7d'})
|
||||
} catch(err) {
|
||||
if (err.name === "TokenExpiredError"){
|
||||
throw new Error ("Error: Token Expired. Please request new invitation or apply to the team again")
|
||||
} else {
|
||||
throw new Error (`Error: Token error - ${err.message}`)
|
||||
}
|
||||
}
|
||||
|
||||
console.log('verifyInviteToken', verifiedToken)
|
||||
return verifiedToken
|
||||
}
|
||||
|
||||
module.exports = { sendTeamMemberInvite, verifyInviteToken }
|
||||
+19
-1
@@ -14,7 +14,7 @@ const { getMember } = require('./auth/middleware/getMember')
|
||||
const { validateIdToken } = require('./auth/validateIdToken')
|
||||
const { directiveResolvers } = require('./auth/authDirectives')
|
||||
|
||||
const { sendTeamMemberInvite } = require('./email/sendgrid')
|
||||
const { sendTeamMemberInvite, verifyInviteToken } = require('./email/sendgrid')
|
||||
|
||||
const {
|
||||
createStoragePipline,
|
||||
@@ -136,6 +136,24 @@ const resolvers = {
|
||||
}
|
||||
return member
|
||||
},
|
||||
async verifyTeamInvite(parent, { token }, ctx, info) {
|
||||
let verifiedToken = null
|
||||
let team = null
|
||||
try {
|
||||
verifiedToken = await verifyInviteToken(token)
|
||||
team = {
|
||||
email: verifiedToken.email,
|
||||
team: {
|
||||
slug: verifiedToken.team
|
||||
}
|
||||
}
|
||||
console.log('verifyTeamInvite.token: ', await verifiedToken)
|
||||
} catch (err) {
|
||||
console.log('verifyTeamInvite. err: ', err)
|
||||
throw new Error(err.message)
|
||||
}
|
||||
return team
|
||||
},
|
||||
async createTeam(parent, { name, slug }, ctx, info) {
|
||||
const authId = ctx.request.user.sub
|
||||
return ctx.db.mutation.createTeam({ data: { name: name, slug: slug, owner: authId, members: { create: { member:{ connect:{ authId: authId} }, role: 'OWNER' } }, profile:{create:{avatar:"a"} } } }, TEAMS_FRAGMENT)
|
||||
|
||||
@@ -20,6 +20,7 @@ type Query {
|
||||
|
||||
type Mutation {
|
||||
authenticate(idToken: String!): Member
|
||||
verifyTeamInvite(token: String!): TeamMembers
|
||||
createTeam(name: String!, slug: String!): Team @isAuthenticated
|
||||
updateTeamProfile(slug: String!, description: String, motto: String, avatar: String, banner: String): Team @isAuthenticated
|
||||
deleteTeam(slug: String!): Team @isAuthenticated @isOwner(type: "Team")
|
||||
|
||||
Generated
+25
-8
@@ -6266,8 +6266,7 @@
|
||||
"decode-uri-component": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz",
|
||||
"integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=",
|
||||
"dev": true
|
||||
"integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU="
|
||||
},
|
||||
"decompress-response": {
|
||||
"version": "3.3.0",
|
||||
@@ -12102,6 +12101,18 @@
|
||||
"prepend-http": "^1.0.0",
|
||||
"query-string": "^4.1.0",
|
||||
"sort-keys": "^1.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"query-string": {
|
||||
"version": "4.3.4",
|
||||
"resolved": "https://registry.npmjs.org/query-string/-/query-string-4.3.4.tgz",
|
||||
"integrity": "sha1-u7aTucqRXCMlFbIosaArYJBD2+s=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"object-assign": "^4.1.0",
|
||||
"strict-uri-encode": "^1.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"npm-run-all": {
|
||||
@@ -13791,13 +13802,19 @@
|
||||
"integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA=="
|
||||
},
|
||||
"query-string": {
|
||||
"version": "4.3.4",
|
||||
"resolved": "https://registry.npmjs.org/query-string/-/query-string-4.3.4.tgz",
|
||||
"integrity": "sha1-u7aTucqRXCMlFbIosaArYJBD2+s=",
|
||||
"dev": true,
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/query-string/-/query-string-6.1.0.tgz",
|
||||
"integrity": "sha512-pNB/Gr8SA8ff8KpUFM36o/WFAlthgaThka5bV19AD9PNTH20Pwq5Zxodif2YyHwrctp6SkL4GqlOot0qR/wGaw==",
|
||||
"requires": {
|
||||
"object-assign": "^4.1.0",
|
||||
"strict-uri-encode": "^1.0.0"
|
||||
"decode-uri-component": "^0.2.0",
|
||||
"strict-uri-encode": "^2.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"strict-uri-encode": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz",
|
||||
"integrity": "sha1-ucczDHBChi9rFC3CdLvMWGbONUY="
|
||||
}
|
||||
}
|
||||
},
|
||||
"querystring": {
|
||||
|
||||
@@ -89,6 +89,7 @@
|
||||
"graphql": "^0.13.2",
|
||||
"graphql-tag": "^2.9.2",
|
||||
"prop-types": "^15.6.2",
|
||||
"query-string": "^6.1.0",
|
||||
"react": "^16.5.0",
|
||||
"react-apollo": "^2.1.11",
|
||||
"react-dom": "^16.5.0",
|
||||
|
||||
@@ -19,6 +19,7 @@ import {
|
||||
NavBar,
|
||||
Footer,
|
||||
Callback,
|
||||
AcceptTeamInvite,
|
||||
Home,
|
||||
About,
|
||||
Dashboard,
|
||||
@@ -171,6 +172,11 @@ class App extends Component {
|
||||
return <Callback {...props} />
|
||||
}}
|
||||
/>
|
||||
<Route
|
||||
exact
|
||||
path='/activate-team-membership'
|
||||
render={props => <AcceptTeamInvite {...props} auth={auth} />}
|
||||
/>
|
||||
</Switch>
|
||||
<Footer />
|
||||
</div>
|
||||
|
||||
@@ -16,7 +16,19 @@ const AUTHENTICATE = gql`
|
||||
}
|
||||
}
|
||||
`
|
||||
const lock = new Auth0Lock(AUTH_CONFIG.clientId, AUTH_CONFIG.domain, {
|
||||
|
||||
const VERIFY_TEAM_INVITE = gql`
|
||||
mutation verifyTeamInvite($token: String!) {
|
||||
verifyTeamInvite(token: $token) {
|
||||
email
|
||||
team {
|
||||
slug
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
export const defaultOptions = {
|
||||
oidcConformant: true,
|
||||
autoclose: true,
|
||||
auth: {
|
||||
@@ -28,7 +40,27 @@ const lock = new Auth0Lock(AUTH_CONFIG.clientId, AUTH_CONFIG.domain, {
|
||||
scope: `openid profile email user_metadata app_metadata picture`
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export const inviteOptions = {
|
||||
oidcConformant: true,
|
||||
autoclose: false,
|
||||
allowedConnections: ['Username-Password-Authentication'],
|
||||
allowShowPassword: true,
|
||||
auth: {
|
||||
sso: false,
|
||||
redirectUrl: window.location.origin + '/callback',
|
||||
responseType: 'token id_token',
|
||||
audience: `${AUTH_CONFIG.api_audience}`,
|
||||
params: {
|
||||
state: '',
|
||||
scope: `email`
|
||||
}
|
||||
},
|
||||
prefill: { email: '' }
|
||||
}
|
||||
|
||||
let lock = new Auth0Lock(AUTH_CONFIG.clientId, AUTH_CONFIG.domain, defaultOptions)
|
||||
|
||||
class Auth {
|
||||
constructor (cb, apolloClient) {
|
||||
@@ -37,6 +69,7 @@ class Auth {
|
||||
this.apolloClient = apolloClient
|
||||
this.cb = cb.bind(this)
|
||||
this.login = this.login.bind(this)
|
||||
this.loginInvite = this.loginInvite.bind(this)
|
||||
this.logout = this.logout.bind(this)
|
||||
this.isAuthenticated = this.isAuthenticated.bind(this)
|
||||
this.checkSession = this.checkSession.bind(this)
|
||||
@@ -47,6 +80,29 @@ class Auth {
|
||||
lock.show()
|
||||
}
|
||||
|
||||
async loginInvite (jwt) {
|
||||
let email
|
||||
let team
|
||||
try {
|
||||
const data = await client.mutate({
|
||||
mutation: VERIFY_TEAM_INVITE,
|
||||
variables: { token: jwt }
|
||||
})
|
||||
|
||||
console.log('loginInvite auth: ', await data.data.verifyTeamInvite)
|
||||
setItem('invite', JSON.stringify(data.data.verifyTeamInvite))
|
||||
|
||||
email = data.data.verifyTeamInvite.email
|
||||
team = data.data.verifyTeamInvite.team.slug
|
||||
} catch (err) {
|
||||
return console.log('loginInvite err: ', err)
|
||||
}
|
||||
inviteOptions.prefill.email = email
|
||||
inviteOptions.auth.params.state = `${email}|${team}`
|
||||
let lockInvite = new Auth0Lock(AUTH_CONFIG.clientId, AUTH_CONFIG.domain, inviteOptions)
|
||||
lockInvite.show()
|
||||
}
|
||||
|
||||
handleAuthentication () {
|
||||
// Add a callback for Lock's `authenticated` event
|
||||
lock.on('authenticated', this.setSession.bind(this))
|
||||
|
||||
@@ -5,6 +5,7 @@ import Home from './home'
|
||||
import About from './about'
|
||||
import Dashboard from './dashboard'
|
||||
import Teams from './teams'
|
||||
import AcceptTeamInvite from './teams/AcceptTeamInvite'
|
||||
|
||||
import { theme, globalStyles } from './theme'
|
||||
|
||||
@@ -12,6 +13,7 @@ export {
|
||||
NavBar,
|
||||
Footer,
|
||||
Callback,
|
||||
AcceptTeamInvite,
|
||||
Home,
|
||||
About,
|
||||
Dashboard,
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
import React, { Component } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
import queryString from 'query-string'
|
||||
|
||||
import { MessageCard } from '../common/'
|
||||
|
||||
class AcceptTeamInvite extends Component {
|
||||
render () {
|
||||
const { location, auth } = this.props
|
||||
const param = queryString.parse(location.search)
|
||||
console.log(param, auth)
|
||||
|
||||
if (auth === undefined) {
|
||||
return <MessageCard message='Loading...' />
|
||||
}
|
||||
|
||||
auth.loginInvite(param.token)
|
||||
|
||||
return (
|
||||
<MessageCard message='Verifying Invitation' />
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
AcceptTeamInvite.propTypes = {
|
||||
location: PropTypes.object.isRequired,
|
||||
auth: PropTypes.object
|
||||
}
|
||||
|
||||
export default AcceptTeamInvite
|
||||
Reference in new issue
Block a user