Skip to content
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

Expose identity token for oauth2 #3211

Merged
merged 18 commits into from
Apr 5, 2021

Conversation

sayoojs
Copy link
Contributor

@sayoojs sayoojs commented Mar 19, 2021

Closes #1423

Exposed identity token in the UI for all grant types in Oauth2.
image

Shows both identity token and refresh token in the Ctrl+Space autocomplete list for ease of use.
image

Made sure to handle populating identity token on clicking the Refresh Token button.

@vercel
Copy link

vercel bot commented Mar 19, 2021

This pull request is being automatically deployed with Vercel (learn more).
To see the status of your deployment, click below or on the icon next to each commit.

🔍 Inspect: https://vercel.com/teaminsomnia/insomnia-storybook/6RWqWc3Kfcrud3HMf2XmKo97aX3E
✅ Preview: Canceled

[Deployment for ff90aef canceled]

Copy link
Contributor

@develohpanda develohpanda left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generally looks good but a couple of changes to make here 😄

I am also not set up to be able to QA this, if you could outline some of your QA steps to show this works and fails correctly that would be very much appreciated.

plugins/insomnia-plugin-request/index.js Outdated Show resolved Hide resolved
@vercel
Copy link

vercel bot commented Mar 22, 2021

@sayoojs is attempting to deploy a commit to the Insomnia Team on Vercel.

A member of the Team first needs to authorize it.

@sayoojs
Copy link
Contributor Author

sayoojs commented Mar 22, 2021

@develohpanda The QA I've done so far is

  • With 'Grant Type' as Authorization Code, tried querying an endpoint protected by AWS Cognito user pools which uses the identityToken as Bearer. Successfully retrieved a 200.
  • In cases where there is no identityToken returned by the auth provider, the input field will show n/a, and 'No token' message is shown on auto complete(Ctrl+Space).(Emulated the null return by manually removing the return for this attribute from the get function)
    • In case of either an empty string value or a null. Checked if the 'No token' message showed up on the autocomplete tag's edit screen.
  • Have NOT tested any of the other grant types due to not having any existing environments which uses those authentication grant methods at hand. This is a concern.

image
image

I've also made the requested changes and pushed the commit, but since I forked, Vercel, is asking for authentication.

@vercel vercel bot temporarily deployed to Preview March 22, 2021 06:24 Inactive
Copy link
Contributor

@develohpanda develohpanda left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the quick turnaround and your notes! 🙌🏽

I am happy with the code and usability though I'm not sure about the expectation for token expiry (should it be the same as the access token?). We may also need to explore how to QA this, maybe allowing users from the parent issue to QA a beta build.

@DMarby may have some thoughts on QA as well.

plugins/insomnia-plugin-request/index.js Show resolved Hide resolved
@sayoojs
Copy link
Contributor Author

sayoojs commented Mar 26, 2021

Hi @develohpanda

I've pushed another commit which addresses handling the Identity Token expiry separately.
What I've done is decode the identityToken JWT to fetch the exp and render the expiry from that value.
So on the off chance the expiry for the identity token is different from that of the access token, it should render differently.

Also, any updates on including this in a beta build?

Thanks in advance! 😃

@develohpanda
Copy link
Contributor

Awesome! I will review again, and I'll raise it with the team next week to make sure we get some more reviews on this PR and figure out a way forward. 🤗

Copy link
Contributor

@develohpanda develohpanda left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice 🎉

make it exactly 13 digits. As the 'TimeFromNow' component only seems to
render 13 digit epochs correctly.
*/
const expDigitCount = exp.toString().length;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like it's using moment to create the timestamp.

What does the expiry extracted from the token look like/represent? Feels like the padding or removing of digits could cause some strange behavior 🤔

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The extracted expiry for identityToken was a 10 digit epoch representation in my case (Eg: 1617202697 Precision up to seconds).
For accessToken's expires_in key its 13 digit epoch (Eg: 1617202697111 Precision up to milliseconds).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see! Reading some docs about the JWT exp property it seems this is usually in seconds. Is this always the case or situational? If always, I'd be more comfortable with a solution what converts seconds to milliseconds by multiplying by 1000, rather than removing or padding digits 🤔 since we're working with numbers the multiplication seems easier to follow.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh no, by padding (as shown in snippet below) that's what I'm doing.

I'm essentially dividing or multiplying by 10^n, where n is calculated as the difference between the number 13 and the actual digit count of epoch generated from the JWT exp property.

exp = exp * 10 ** (13 - expDigitCount);

So in cases of epoch seconds, that code multiplies by 10^3.
In case of epoch microseconds, that code multiplies by 10^-3. Which essentially remove the digits that representing the microseconds.

Maybe I should force cast the result to big int to prevent floating points on x10^-n

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahhhh okay, thanks for explaining that!!

Maybe I should force cast the result to big int to prevent floating points on x10^-n

That sounds reasonable.

I think it would be good to extract these few lines into a standalone utility method somewhere and writing a few tests as a way to document input/output of this logic. 🙌🏽

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Which lines specifically? The padding/trimming part?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep! The padding and trimming

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a file with preexisting util functions? Where I can export this to? Or do I just create a static method within this class itself?

Copy link
Contributor

@develohpanda develohpanda Apr 1, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This might be a good place! Looks like there a similar helper here too, for snapping a number to a minimum or maximum.

export function snapNumberToLimits(value: number, min?: number, max?: number): number {

The associated tests would go in here: https://github.com/Kong/insomnia/blob/develop/packages/insomnia-app/app/common/__tests__/misc.test.js

Copy link
Contributor Author

@sayoojs sayoojs Apr 5, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved this functionality to misc.js and added tests. (Do review the tests, this is the first time I've written JS tests)

@vercel vercel bot temporarily deployed to Preview March 30, 2021 21:59 Inactive
Copy link
Contributor

@develohpanda develohpanda left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a bug here such that window.atob() fails fatally if the identity token is not encoded correctly (if you just type anything into the input field). The field has a requirement to be encoded in a particular way from what I can see, which is fine, but there shouldn't be a UI failure if it's not encoded as expected. 🤔

image

Another bug in comments below. Once these are fixed up I can trigger an alpha build, or you can bundle it locally for your OS by running npm run app-package:smoke and fetching artefacts from the packages/insomnia-app/dist folder.

Comment on lines 500 to 505
static renderExpiryFromJWT(token: string): React.Element<*> | string | null {
if (!token) {
return null;
}

const base64Url = token.split('.')[1];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just pulled this down locally to test and the Oauth2 tab fails to render for a brand new request as a result of this implementation. The following suggestion matches how renderExpireAt is written

Suggested change
static renderExpiryFromJWT(token: string): React.Element<*> | string | null {
if (!token) {
return null;
}
const base64Url = token.split('.')[1];
static renderExpiryFromJWT(token: ?OAuth2Token): React.Element<*> | string | null {
if (!token || !token.identitiyToken) {
return null;
}
const base64Url = token.identitiyToken.split('.')[1];

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll make this change.
I was trying to keep the function generic, to be able to be used with any JWT 😅
I guess since accessToken already has an expiry function, i'll make this one dedicated to identityToken.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair enough 😅 it fails because likely somewhere in the render loop this logic is reached while token is undefined, and the previous code would fail with an error like identityToken cannot be found on undefined

@@ -541,7 +580,8 @@ class OAuth2Auth extends React.PureComponent<Props, State> {
const { request, oAuth2Token: tok } = this.props;
const { loading, error, showAdvanced } = this.state;

const expireLabel = OAuth2Auth.renderExpireAt(tok);
const accessExpireLabel = OAuth2Auth.renderExpireAt(tok);
const identityExpireLabel = OAuth2Auth.renderExpiryFromJWT(tok.identityToken);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const identityExpireLabel = OAuth2Auth.renderExpiryFromJWT(tok.identityToken);
const identityExpireLabel = OAuth2Auth.renderExpiryFromJWT(tok);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This fix is implemented.

@sayoojs
Copy link
Contributor Author

sayoojs commented Apr 5, 2021

@develohpanda I've implemented the requested changes.

Any idea why the Ubuntu tests might be failing? I couldn't infer anything from the logs. Could you try re-triggering it?

Copy link
Contributor

@develohpanda develohpanda left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you so much 🙏🏽 Sometimes Spectron (the E2E test framework we use for Electron) fails to connect to the chrome driver and gives cryptic errors like that. I have re-triggered, no action needed from your side 🤗

@dimitropoulos dimitropoulos merged commit 351afde into Kong:develop Apr 5, 2021
@kateefimova-eb
Copy link

What an amazing feature! Thank you so much 👏

danelowe added a commit to danelowe/insomnia that referenced this pull request Jun 13, 2022
Kong#3211 Allowed for using an identity token for auth rather than auth token. When using that feature, the GraphQL schema could not be fetched due to `throw new Error('No OAuth 2.0 identity tokens found for request');`. This commit moves the normalization of the request ID further up the chain so it can be used where this error would otherwise be thrown.
danelowe added a commit to danelowe/insomnia that referenced this pull request Jun 13, 2022
Kong#3211 Allowed for using an identity token for auth rather than auth token. When using that feature, the GraphQL schema could not be fetched due to `throw new Error('No OAuth 2.0 identity tokens found for request');`. This commit moves the normalization of the request ID further up the chain so it can be used where this error would otherwise be thrown.
filfreire pushed a commit to danelowe/insomnia that referenced this pull request Nov 18, 2022
Kong#3211 Allowed for using an identity token for auth rather than auth token. When using that feature, the GraphQL schema could not be fetched due to `throw new Error('No OAuth 2.0 identity tokens found for request');`. This commit moves the normalization of the request ID further up the chain so it can be used where this error would otherwise be thrown.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Feature Request] OAuth 2 missing Identity token.
4 participants