-
Notifications
You must be signed in to change notification settings - Fork 25
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
Move JWT from cookie store to Authorization header #2158
Conversation
api/auth/session.js
Outdated
expiresIn: `${process.env.SESSION_LIFETIME_MINUTES}m` | ||
} | ||
), | ||
signWebToken({ payload: session.content }), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Extracted common functionality in this file into functions (signWebToken
, verifyWebToken
) within api/auth/jwtUtils.js
This deploy was cleaned up. |
cf9fc59
to
f74b416
Compare
Sorry this is such a massive change! 😬 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Only a few minor changes. I prefixed those comments with:
change
to make them easier to find. There's also one that's ripe for discussion about whether /auth/logout
should ever return error statuses. On the whole, though, this PR looks really good. It's a nice, clean implementation!
|
||
const defaultStrategies = [new LocalStrategy(authenticate())]; | ||
const passportLocalStrategy = new LocalStrategy(authenticate()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a sensible change. The reason it was originally an array is we thought we would soon need to support more than one strategy - local for dev, and CMS's central auth service in production. That will eventually still be the case, but I like this being simpler in the meantime. 👍
'/auth/login', | ||
passport.authenticate('local', { session: false }), | ||
(req, res) => { | ||
serializeUser(req.user, (err, sessionId) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since serializeUser
is only used by our custom code now instead of being used by the Passport session library, it doesn't have to conform to that API anymore. We should look into how we can refactor it to be easier to use/maintain. (Added issue #2206 to track that as future work.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for documenting that!
api/auth/index.js
Outdated
// login routes. | ||
const jwtExcludedRoutes = ['/auth/login/nonce', '/auth/login']; | ||
app.use((req, res, next) => | ||
jwtExcludedRoutes.includes(req.originalUrl) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🤔 I wonder how this is affected by proxying. It's probably fine, but we should double-check in a preview deployment because those create a proxy from /api
to /
. If originalUrl
is /api/auth/login/nonce
, that could break this. But again... I bet it's fine. I think Express generally ignores proxies.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, I was thinking about this yesterday evening. If I rely on the jwtMiddleware
to only deserialize the user if the Authorization header is present (e.g. remove the res.send(400).end()
), and rely on can
and loggedIn
to manage sending 401
and 403
responses, I can get rid of this funky excluded routes thing.
jwtExtractor, | ||
signWebToken, | ||
verifyWebToken | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Putting all of the JWT-related stuff in one place makes me so happy. 👍 👍
api/routes/openAPI/auth.js
Outdated
400: { | ||
description: 'Not logged in' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same thing with the error on logging out
description: 'Not logged in' | ||
}, | ||
403: { | ||
description: 'Not logged in' | ||
description: 'Does not have permission to this activity' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
😂 Thank you!
bearerAuth: { | ||
type: 'http', | ||
scheme: 'bearer', | ||
bearerFormat: 'Bearer xxx.yyy.zzz' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice 👍
const store = mockStore({}); | ||
fetchMock | ||
.onPost('/auth/login/nonce', { username: 'name' }) | ||
.reply(200, { nonce: '123abc' }); | ||
fetchMock | ||
.onPost('/auth/login', { username: '123abc', password: 'secret' }) | ||
.reply(200, { moop: 'moop', activities: [] }); | ||
.reply(200, { user: { moop: 'moop', activities: [] }, token: 'xxx.yyy.zzz' }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good ol' moop moop
@mgwalker I'm pretty sure I've addressed all your requested changes. Please, take a look... I have a few questions for you:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me!
return token; | ||
const token = req.get('Authorization'); | ||
if (!token || !token.toLowerCase().match(/^bearer\s.+\..+\..+/)) return null; | ||
const [temp, result] = token.split(' '); // eslint-disable-line no-unused-vars |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As a future note, one convention for throwaway destructured values would be something like:
const [_, result] = ...
And then the linter won't complain. Only trouble is you can't do that if you have more than one throwaway variable. 😛
const scenarios = [ | ||
['Bearer xxx.yyy.zzz', 'xxx.yyy.zzz', 'returns the JWT'], | ||
['bearer xxx.yyy.zzz', 'xxx.yyy.zzz', 'returns the JWT'], | ||
['bearer', null, 'returns null'], | ||
['bearer ', null, 'returns null'], | ||
['', null, 'returns null'], | ||
['Elephanter xxx.yyy.zzz', null, 'returns null'] | ||
]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice!
Notes to Design and Product: This is a back-end change, so you shouldn't see any changes in UI. Verify that this is functional by signing in and out. That's it! |
725a735
to
66952d4
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Logged in and logged out. :)
Codecov Report
@@ Coverage Diff @@
## master #2158 +/- ##
=======================================
Coverage 92.99% 92.99%
=======================================
Files 219 219
Lines 4214 4214
Branches 658 658
=======================================
Hits 3919 3919
Misses 273 273
Partials 22 22 Continue to review full report at Codecov.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can only verify this in Firefox -- but it looks like the rest of the team is good. Gtg.
Resolves #2100
This pull request...
This pull request is ready to merge when...
The experience passes a basic manual accessibility audit (keyboard nav, screenreader, text scaling) OR an exemption is documentedno UI changesThis feature is done when...