This repository has been archived by the owner on Oct 21, 2020. It is now read-only.
-
-
Notifications
You must be signed in to change notification settings - Fork 28
Add auth options 🎉 #58
Merged
Merged
Changes from 15 commits
Commits
Show all changes
17 commits
Select commit
Hold shift + click to select a range
076cb5e
feat(auth): add auth options :tada:
Bouncey a2bb7ce
feat(tools): add debug
Bouncey 6119221
fix(directives): allow graphql-tools to handle directive resolvers
Bouncey 17f2be5
fix(auth-errors): communicate verification errors to the client
Bouncey 87311b7
feat(jwt-cert): add cert to process.env
Bouncey ecbdf67
chore(pem): remove references to .pem files
Bouncey ebddc65
chore(dependencies): add new packages to yarn.lock
Bouncey 46927bb
fix(jwt-cert): add jwt-cert to serverless.yml
Bouncey 892d8e1
chore(tools): add jwt-cert to depoly script
Bouncey affa862
feat(tools): add initial directive tests scaffolding
Bouncey f9362bc
feat: support authentication in tests
ojongerius ea41974
chore(tools): refactor integration tests
Bouncey c83b051
feat(tools): add directive tests
Bouncey 571a6c5
chore(tools): remove gulp in favour of cross-env
Bouncey db07ab0
chore(deps): remove package-lock.json
Bouncey 168fca4
remove dev-only code
Bouncey 8dd4715
chore(tools): fix for ci
Bouncey File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import jwt from 'jsonwebtoken'; | ||
import debug from 'debug'; | ||
|
||
import { AuthorizationError } from '../graphql/errors'; | ||
|
||
const log = debug('fcc:auth'); | ||
const { JWT_CERT, NODE_ENV } = process.env; | ||
|
||
export function verifyWebToken(ctx) { | ||
log('Verifying token'); | ||
const token = ctx && ctx.headers && ctx.headers.authorization; | ||
if (!token) { | ||
throw new AuthorizationError({ | ||
message: 'You must supply a JSON Web Token for authorization!' | ||
}); | ||
} | ||
let decoded = null; | ||
let error = null; | ||
try { | ||
decoded = jwt.verify(token.replace('Bearer ', ''), JWT_CERT, { | ||
ignoreExpiration: NODE_ENV === 'test' | ||
}); | ||
} catch (err) { | ||
error = err; | ||
} finally { | ||
return { decoded, error, isAuth: !!decoded }; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,9 @@ | ||
require('dotenv').config(); | ||
|
||
const { MONGODB_URL, GRAPHQL_ENDPOINT_URL } = process.env; | ||
const { MONGODB_URL, GRAPHQL_ENDPOINT_URL, JWT_CERT } = process.env; | ||
|
||
exports.getSecret = () => ({ | ||
MONGODB_URL, | ||
GRAPHQL_ENDPOINT_URL | ||
GRAPHQL_ENDPOINT_URL, | ||
JWT_CERT, | ||
MONGODB_URL | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
import { createError } from 'apollo-errors'; | ||
|
||
export const AuthorizationError = createError('AuthorizationError', { | ||
message: 'You are not authorized.' | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
/* global expect beforeEach */ | ||
import sinon from 'sinon'; | ||
import sinonStubPromise from 'sinon-stub-promise'; | ||
import { createDirectives } from './directives'; | ||
|
||
sinonStubPromise(sinon); | ||
const testErrorMsg = 'Test error message'; | ||
let nextSpy = sinon.spy(); | ||
let nextPromiseStub = sinon.stub().returnsPromise(); | ||
let authTrueStub = sinon.stub().returns({ isAuth: true }); | ||
let authFalseStub = sinon | ||
.stub() | ||
.returns({ isAuth: false, error: { message: testErrorMsg } }); | ||
|
||
beforeEach(() => { | ||
authFalseStub.resetHistory(); | ||
authTrueStub.resetHistory(); | ||
nextSpy.resetHistory(); | ||
nextPromiseStub.resetHistory(); | ||
}); | ||
|
||
describe('isAuthenticatedOnField', () => { | ||
it('should return null if authenication fails', () => { | ||
const { isAuthenticatedOnField } = createDirectives(authFalseStub); | ||
const secretValue = 'secret squirrel'; | ||
nextPromiseStub.resolves(secretValue); | ||
const result = isAuthenticatedOnField(nextPromiseStub); | ||
|
||
expect(authFalseStub.calledOnce).toBe(true); | ||
expect(result.resolved).toBe(true); | ||
expect(result.resolveValue).toBe(null); | ||
}); | ||
|
||
it('should return the secretValue if authentication succeeds', () => { | ||
const { isAuthenticatedOnField } = createDirectives(authTrueStub); | ||
const secretValue = 'secret squirrel'; | ||
nextPromiseStub.resolves(secretValue); | ||
const result = isAuthenticatedOnField(nextPromiseStub); | ||
|
||
expect(authTrueStub.calledOnce).toBe(true); | ||
expect(result.resolved).toBe(true); | ||
expect(result.resolveValue).toBe(secretValue); | ||
}); | ||
}); | ||
|
||
describe('isAuthenticatedOnQuery', () => { | ||
it('should throw an error is auth fails', () => { | ||
const { isAuthenticatedOnQuery } = createDirectives(authFalseStub); | ||
|
||
expect(() => { | ||
isAuthenticatedOnQuery(nextSpy); | ||
}).toThrowError(testErrorMsg); | ||
expect(nextSpy.called).toBe(false); | ||
}); | ||
|
||
it('should call next if auth succeeds', () => { | ||
const { isAuthenticatedOnQuery } = createDirectives(authTrueStub); | ||
isAuthenticatedOnQuery(nextPromiseStub); | ||
|
||
expect(nextPromiseStub.calledOnce).toBe(true); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import { AuthorizationError } from '../errors'; | ||
import { verifyWebToken as _verifyWebToken } from '../../auth'; | ||
import { asyncErrorHandler } from '../../utils'; | ||
|
||
/* | ||
Interface: { | ||
Directive: ( | ||
next: Resolver <Promise> | ||
source: any <From Data Source>, Example <User Object> | ||
args: any, passed to directive | ||
ctx: Lambda context <Object> | ||
) => <Promise> | <Error> | ||
} | ||
*/ | ||
|
||
export const createDirectives = (verifyWebToken = _verifyWebToken) => ({ | ||
isAuthenticatedOnField: (next, source, args, ctx) => { | ||
const { isAuth } = verifyWebToken(ctx); | ||
return asyncErrorHandler(next().then(result => (isAuth ? result : null))); | ||
}, | ||
isAuthenticatedOnQuery: (next, source, args, ctx) => { | ||
const { isAuth, error } = verifyWebToken(ctx); | ||
if (isAuth) { | ||
return asyncErrorHandler(next()); | ||
} | ||
throw new AuthorizationError({ | ||
message: `You are not authorized, ${error.message}` | ||
This comment was marked as off-topic.
Sorry, something went wrong. |
||
}); | ||
} | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,5 @@ | ||
import { mergeResolvers } from 'merge-graphql-schemas'; | ||
import { userResolvers } from './user'; | ||
|
||
export { createDirectives } from './directives'; | ||
export default mergeResolvers([userResolvers]); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,6 +4,6 @@ type Query { | |
_id: ID | ||
name: String | ||
email: String | ||
): [User] | ||
): [User] @isAuthenticatedOnQuery | ||
} | ||
`; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,6 @@ | ||
export default ` | ||
type User { | ||
_id: ID! | ||
_id: ID @isAuthenticatedOnField | ||
email: String | ||
name: String | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
export default ` | ||
directive @isAuthenticatedOnField on FIELD | FIELD_DEFINITION | ||
directive @isAuthenticatedOnQuery on FIELD | FIELD_DEFINITION | ||
`; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,5 @@ | ||
import { mergeTypes } from 'merge-graphql-schemas'; | ||
import User from './User'; | ||
import directives from './directives'; | ||
|
||
export default mergeTypes([User]); | ||
export default mergeTypes([User, directives]); |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
module.exports = { | ||
globalSetup: './test/utils/setup.js', | ||
globalTeardown: './test/utils/teardown.js', | ||
testEnvironment: './test/utils/mongo-environment.js' | ||
testEnvironment: './test/utils/test-environment.js' | ||
}; |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This comment was marked as off-topic.
Sorry, something went wrong.