-
Notifications
You must be signed in to change notification settings - Fork 70
fix(sdk-auth): to encode request body #1581
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
Conversation
| const isNotRefreshTokenGrantType = grantType !== 'refresh_token' | ||
| const initialBody = encode({ | ||
| grant_type: grantType, | ||
| ...(disableRefreshToken && { refresh_token: false }), | ||
| ...(isNotRefreshTokenGrantType && { scope }), | ||
| }) |
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.
Building up the initial request encoding all params.
| static _appendToRequestBody( | ||
| request: AuthRequest, | ||
| toAppend: Object | ||
| ): AuthRequest { | ||
| const previousDecodedRequestBody = request.body ? decode(request.body) : {} | ||
| const nextEncdedRequestBody = encode({ | ||
| ...previousDecodedRequestBody, | ||
| ...toAppend, | ||
| }) | ||
| request.body = nextEncdedRequestBody | ||
|
|
||
| return request |
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.
A small helper reused within the module just to append to the request cause that's what we do most of the time here.
| static _appendToRequestBody( | ||
| request: AuthRequest, | ||
| toAppend: Object | ||
| ): AuthRequest { |
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.
We return the request not just the body here. That makes this easier to compose from my perspective.
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 like this change a lot 👍
| anonymousFlow(anonymousId: string = '', config: CustomAuthOptions = {}) { | ||
| const _config = this._getRequestConfig(config) | ||
| const request = SdkAuth._buildRequest( | ||
| let request = SdkAuth._buildRequest( |
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.
We build the request, then append to its body and get a new request. That's what I mean by composing.
Codecov Report
@@ Coverage Diff @@
## master #1581 +/- ##
=======================================
Coverage 98.63% 98.63%
=======================================
Files 128 128
Lines 3305 3307 +2
Branches 761 760 -1
=======================================
+ Hits 3260 3262 +2
Misses 41 41
Partials 4 4
Continue to review full report at Codecov.
|
|
@daern91 please assign anybody else if needed. You seem to be most familiar with this however so maybe a good reviewer 😄. |
daern91
left a comment
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 this one. Much cleaner now with a proper lib and not the hacky template strings 👍
Would also be nice to have the ability to use the, supposedly faster, querystring.stringify native solution in node. As described here: https://github.com/lukeed/qss#qss-
But OTOH it's probably not necessary and can be implemented at a later stage if needed.
packages/sdk-auth/src/auth.js
Outdated
| toAppend: Object | ||
| ): AuthRequest { | ||
| const previousDecodedRequestBody = request.body ? decode(request.body) : {} | ||
| const nextEncdedRequestBody = encode({ |
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.
nitpick typo:
nextEncdedRequestBody
nextEncodedRequestBody
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. Feel free to use GitHub's review suggestions next time. Helps to get better diffs of what you carefully markdowned yerself :)
| static _appendToRequestBody( | ||
| request: AuthRequest, | ||
| toAppend: Object | ||
| ): AuthRequest { |
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 like this change a lot 👍
| username: string, | ||
| password: string | ||
| ): string { | ||
| ): AuthRequest { |
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.
Here too 👍
|
|
||
| if (anonymousId) request.body += `&anonymous_id=${anonymousId}` | ||
| if (anonymousId) | ||
| request = SdkAuth._appendToRequestBody(request, { |
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 guess we could technically leave request as a constant and return here instead of re-assigning and returning below. Just a matter of flavor tho.
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.
Yes, didn't want to change such things much in this PR. Generally the composition in this code can be improve. Ideally, the AuthRequeust could have a map and value function. Then you could just request.map(SdkAuth._appendToRequestBody(...)) which gives you a mapped request and then value() when you pass it somewhere. That's another story though.
| username, | ||
| password | ||
| ) | ||
| request = SdkAuth._appendUserCredentialsToBody(request, username, password) |
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 with this one, but might just make things too nested and unreadable.
| request.body = SdkAuth._appendUserCredentialsToBody( | ||
| request.body, | ||
| request = SdkAuth._appendUserCredentialsToBody( | ||
| request, |
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 see, we keep this pattern throughout 👍
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.
The conditionals are a bit hard to improve without better patterns of compositions. I will adjust those which don't involve them.
|
Adding @commercetools/clients-team as FYI |
|
Encoding LGTM 👍 |
That's a Node.js utility. We also run in the browser. Given we encode three things - as you mentioned - I don't see this, comparing to other impacts, relevant for performance of this lib. With 100k ops yes, not with 3.
I am still not super happy with this. Encapsulation is sub-optimal:
Still this is better than before and step-wise is how to improve things 🐱. |
|
@jenschude any comments on this one before we merge? |
jenschude
left a comment
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.
Just a comment about the testing part
| `grant_type=password&scope=manage_project:${config.projectKey}` + | ||
| `&username=user%204%5El*aJ%40ETso%2B%2F%5CHdE1!x0u4q5` + // encoded | ||
| `&password=pass%204%5El*aJ%40ETso%2B%2F%5CHdE1!x0u4q5` // encoded | ||
| encode({ |
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.
Also it may make the test more readable you are testing the encoding with the function to encode itself. I'm pretty sure that this works correct but a non working the encode function would result in a still working test.
But I also can see that the encode function may not produce a canonical string to compare it to a static string.
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 point. Let me suggest something later :)
I played around a bit. Somehow having the encode feels alright to me. The nock library will throw if a mock is not defined. When expecating on a string I would use Inline Snapshots.
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.
To be on the safe side you could use https://nodejs.org/api/querystring.html#querystring_querystring_encode
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.
Yet another good point 💋. Thanks for being persistent. Here we go: 2913cfe.
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 take the thumbs up as an approval.
Summary
This pull request fixes the
sdk-authpackage to encode the request's body at all times.Description
The
sdk-authis used to perform request authorization in our Node.js SDK. For that it often uses parameters such asscope,refresh_tokenorgrant_typeamong others.The parameters mentioned above can often contain strings which need encoding. This holds true for e.g. the
<scope>:<projectKey>or also thetokenitself.So far the
sdk-authjust concatinated strings to build up the request. For example asbody +=&scope=${scope}. Then sometimes it encodes a parameter asrequest.body +=&refresh_token=${encodeURIComponent(token)}. Our APIs can deal with this inconsistency but it can also cause problems when a string is not rightfully detected as not encoded. This is what I think @cneijenhuis noticed when having problems with token encoding and investigating it.As a result of this this pull request suggests to always encode the body's paramters as it's send as
'Content-Type': 'application/x-www-form-urlencoded'.There are usually two options going about it:
URLSearchParams(web standard)I propose to use qss which is a tiny library which works both in Node.js and the browser. We have good experience with it in the Merchant Center.
Using
URLSearchParamswould need a polyfill as it's not supported in all browsers. Usually leading to larger bundles while we do not need most of it's functionality/API surface.The pull request also updates the tests affected by this which outlines the change.
This overall instead of for example:
gives us