diff options
| author | Wes Bos <wesbos@gmail.com> | 2018-05-15 22:15:36 -0400 |
|---|---|---|
| committer | Wes Bos <wesbos@gmail.com> | 2018-05-15 22:15:36 -0400 |
| commit | 3f9b14e3c1d7f47d9b3e48b94b3b5bf2c722205e (patch) | |
| tree | 63373ce8c75e51305b7899af6c53903ef6c4f179 | |
| parent | ae1a94b08f5aba0c16c6536e388b4dd4a53120fd (diff) | |
migrate to cookies for jwt
| -rw-r--r-- | backend/package-lock.json | 9 | ||||
| -rw-r--r-- | backend/package.json | 1 | ||||
| -rw-r--r-- | backend/src/index.js | 23 | ||||
| -rw-r--r-- | backend/src/resolvers/Mutation.js | 24 | ||||
| -rw-r--r-- | backend/src/resolvers/Query.js | 3 | ||||
| -rw-r--r-- | backend/src/schema.graphql | 1 | ||||
| -rw-r--r-- | frontend/components/Signin.js | 2 | ||||
| -rw-r--r-- | frontend/components/Signout.js | 17 | ||||
| -rw-r--r-- | frontend/components/Signup.js | 2 | ||||
| -rw-r--r-- | frontend/lib/withData.js | 19 | ||||
| -rw-r--r-- | frontend/queries/queries.graphql | 6 |
11 files changed, 71 insertions, 36 deletions
diff --git a/backend/package-lock.json b/backend/package-lock.json index f59765c..fd2a1a7 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -2469,6 +2469,15 @@ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" }, + "cookie-parser": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.3.tgz", + "integrity": "sha1-D+MfoZ0AC5X0qt8fU/3CuKIDuqU=", + "requires": { + "cookie": "0.3.1", + "cookie-signature": "1.0.6" + } + }, "cookie-signature": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", diff --git a/backend/package.json b/backend/package.json index 1ca4ff9..a2c9199 100644 --- a/backend/package.json +++ b/backend/package.json @@ -8,6 +8,7 @@ }, "dependencies": { "bcryptjs": "2.4.3", + "cookie-parser": "^1.4.3", "graphql": "^0.13.2", "graphql-yoga": "1.13.1", "jsonwebtoken": "8.2.1", diff --git a/backend/src/index.js b/backend/src/index.js index 04d13cc..6978225 100644 --- a/backend/src/index.js +++ b/backend/src/index.js @@ -3,14 +3,16 @@ require('dotenv').config({ path: 'variables.env' }); /* eslint-enable */ const jwt = require('jsonwebtoken'); const createServer = require('./createServer'); +const cookieParser = require('cookie-parser'); const server = createServer(); +server.express.use(cookieParser()); + // 1. Check JWT server.express.use((req, res, next) => { - const Authorization = req.get('Authorization'); - if (Authorization) { - const token = Authorization.replace('Bearer ', ''); + const { token } = req.cookies; + if (token) { const { userId } = jwt.verify(token, process.env.APP_SECRET); req.userId = userId; } @@ -30,6 +32,15 @@ server.express.use(async (req, res, next) => { next(); }); -server.start({ port: 4444 }, deets => { - console.log(`Server is running on http://localhost:${deets.port}`); -}); +server.start( + { + cors: { + credentials: true, + origin: process.env.FRONTEND_URL, + }, + port: 4444, + }, + deets => { + console.log(`Server is running on http://localhost:${deets.port}`); + } +); diff --git a/backend/src/resolvers/Mutation.js b/backend/src/resolvers/Mutation.js index 268b348..153833d 100644 --- a/backend/src/resolvers/Mutation.js +++ b/backend/src/resolvers/Mutation.js @@ -22,10 +22,18 @@ const mutations = { info ); - return { - token: jwt.sign({ userId: user.id }, process.env.APP_SECRET), - user, - }; + const token = jwt.sign({ userId: user.id }, process.env.APP_SECRET); + ctx.response.cookie('token', token, { + maxAge: 1000 * 60 * 60 * 24 * 365, + httpOnly: true, + }); + return { user }; + }, + + async signout(parent, args, ctx, info) { + ctx.response.clearCookie('token'); + // TODO: What do we return here? + return { id: 'abc123' }; }, async signin(parent, { email, password }, ctx, info) { @@ -38,8 +46,14 @@ const mutations = { if (!valid) { throw new Error('Invalid password'); } + // set the cookie + const token = jwt.sign({ userId: user.id }, process.env.APP_SECRET); + ctx.response.cookie('token', token, { + maxAge: 1000 * 60 * 60 * 24 * 365, + httpOnly: true, + }); return { - token: jwt.sign({ userId: user.id }, process.env.APP_SECRET), + token, user, }; }, diff --git a/backend/src/resolvers/Query.js b/backend/src/resolvers/Query.js index 276f7fa..b1e0c5b 100644 --- a/backend/src/resolvers/Query.js +++ b/backend/src/resolvers/Query.js @@ -36,8 +36,7 @@ const Query = { }, me(parent, args, ctx, info) { - const Authorization = ctx.request.get('Authorization'); - if (!Authorization || Authorization === 'null') { + if (!ctx.request.userId) { return null; // don't error out, just return nothing } diff --git a/backend/src/schema.graphql b/backend/src/schema.graphql index 5c77d56..14d4797 100644 --- a/backend/src/schema.graphql +++ b/backend/src/schema.graphql @@ -18,6 +18,7 @@ type Mutation { removeFromCart(id: ID!): CartItem createOrder(token: String!): Order! updateUser(name: String): User + signout: User updatePermissions(permissions: [Permission], userId: ID!): User } diff --git a/frontend/components/Signin.js b/frontend/components/Signin.js index f719c60..7a4db8c 100644 --- a/frontend/components/Signin.js +++ b/frontend/components/Signin.js @@ -13,7 +13,7 @@ class Signin extends Component { loginUser = async (e, signin, client) => { e.preventDefault(); const res = await signin(); - localStorage.setItem('token', res.data.signin.token); + // TODO instead of refetching, can we just use the data returned? client.query({ query: CURRENT_USER_QUERY, fetchPolicy: 'network-only' }); }; diff --git a/frontend/components/Signout.js b/frontend/components/Signout.js index 4ef8e6c..fbd7fd9 100644 --- a/frontend/components/Signout.js +++ b/frontend/components/Signout.js @@ -1,20 +1,13 @@ import React, { Component } from 'react'; -import { Query } from 'react-apollo'; -import { CURRENT_USER_QUERY } from '../queries/queries.graphql'; +import { Query, Mutation } from 'react-apollo'; +import { CURRENT_USER_QUERY, SIGN_OUT_MUTATION } from '../queries/queries.graphql'; class Signout extends Component { - signout = refetch => { - console.log(refetch); - console.log('Signing Out'); - localStorage.removeItem('token'); - refetch(); - }; - render() { return ( - <Query query={CURRENT_USER_QUERY}> - {({ refetch }) => <button onClick={() => this.signout(refetch)}>Sign Out</button>} - </Query> + <Mutation mutation={SIGN_OUT_MUTATION} refetchQueries={[{ query: CURRENT_USER_QUERY }]}> + {signout => <button onClick={signout}>Sign Out</button>} + </Mutation> ); } } diff --git a/frontend/components/Signup.js b/frontend/components/Signup.js index e8c639b..22a729f 100644 --- a/frontend/components/Signup.js +++ b/frontend/components/Signup.js @@ -26,7 +26,7 @@ class Signup extends Component { onSubmit={async e => { e.preventDefault(); const res = await signup(); - localStorage.setItem('token', res.data.signup.token); + // TODO can we return theuser from signup? client.query({ query: CURRENT_USER_QUERY, fetchPolicy: 'network-only' }); }} > diff --git a/frontend/lib/withData.js b/frontend/lib/withData.js index 9f7c2a8..0696333 100644 --- a/frontend/lib/withData.js +++ b/frontend/lib/withData.js @@ -6,15 +6,16 @@ import { LOCAL_STATE_QUERY } from '../queries/queries.graphql'; const client = new ApolloClient({ uri: process.env.NODE_ENV === 'development' ? 'http://localhost:4444' : 'http://localhost:4444', ssrMode: !process.browser, // Disables forceFetch on the server (so queries are only run once) - request: operation => { - // if we're in the client and the user has a token, send it along with the request - if (typeof localStorage !== 'undefined' && localStorage.getItem('token')) { - operation.setContext({ - headers: { - authorization: `Bearer ${localStorage.getItem('token')}`, - }, - }); - } + // TODO this is a bug: https://github.com/apollographql/apollo-client/issues/3265 + fetchOptions: { + credentials: 'include', + }, + request: async operation => { + operation.setContext({ + fetchOptions: { + credentials: 'include', + }, + }); }, clientState: { resolvers: { diff --git a/frontend/queries/queries.graphql b/frontend/queries/queries.graphql index 61d5587..22e5f29 100644 --- a/frontend/queries/queries.graphql +++ b/frontend/queries/queries.graphql @@ -36,6 +36,12 @@ mutation SIGNIN_MUTATION($email: String!, $password: String!) { } } +mutation SIGN_OUT_MUTATION { + signout { + id + } +} + mutation REQUEST_RESET_MUTATION($email: String!) { requestReset(email: $email) { id |
