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

feat(validate): allow to pass multiple audiencies #198

Merged
merged 4 commits into from
Sep 25, 2023

Conversation

Dasio
Copy link
Contributor

@Dasio Dasio commented Sep 7, 2023

No description provided.

@@ -28,7 +28,7 @@ export async function getPubKey(

export async function validateIAPToken(
iapToken: string,
expectedAudience: string,
expectedAudiences: string | string[],
Copy link
Collaborator

Choose a reason for hiding this comment

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

2 notes:

  • this is a breaking change, so please add the "BREAKING CHANGE: ..." mention in the commit for this change;
  • I would simplify the signature to be string[] (and migration for existing users would be to just enclose their current expected audience into brackets).

I believe it would simplify the logic down the road.

Suggested change
expectedAudiences: string | string[],
expectedAudiences: string[],

Copy link
Contributor Author

@Dasio Dasio Sep 21, 2023

Choose a reason for hiding this comment

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

I wanted to avoid breaking change, is it breaking change because of changing the name of the parameter? (didn't worked with TS for a few years)

Copy link
Collaborator

Choose a reason for hiding this comment

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

Oh right 🙈 I somehow misread this as an object parameter (e.g. function myFn({ param1: string, param2: string}))

So you're right, it wouldn't be a breaking change by just updating the name of the parameter, my bad.

However, my proposed change of using just string[] as a type (as opposed to extending it like you initially proposed) would be one.

@@ -46,12 +46,22 @@ export async function validateIAPToken(
throw Error(`Invalid IAP issuer [${decoded.payload.iss}]`);
}

const expectedAudienceArray = Array.isArray(expectedAudiences)
Copy link
Collaborator

Choose a reason for hiding this comment

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

This would then become unnecessary.

// From: https://cloud.google.com/iap/docs/signed-headers-howto
// `aud` Must be a string with the following values:
// App Engine: /projects/PROJECT_NUMBER/apps/PROJECT_ID
// Compute Engine and GKE: /projects/PROJECT_NUMBER/global/backendServices/SERVICE_ID
if (decoded.payload.aud !== expectedAudience) {
throw Error(`Invalid audience [${decoded.payload.aud}]`);
if (
Copy link
Collaborator

Choose a reason for hiding this comment

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

All of this might be simplified to:

Suggested change
if (
if (!expectedAudiences.includes(decoded.payload.aud))

From the comment above, it seems the decoded aud should be a string containing only one audience for the given JWT token.

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'm getting

TS2345: Argument of type  string | string[] | undefined  is not assignable to parameter of type  string 
Type  undefined  is not assignable to type  string

Copy link
Collaborator

Choose a reason for hiding this comment

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

From reading the link that's mentioned in the comment, it seems it's expected from us to validate that the decoded audience is indeed a string.

So what you could do is:

Suggested change
if (
if (typeof decoded.payload.aud !== "string") {
throw Error(`Invalid audience: expected a string, received [${decoded.payload.aud}]`);
}
if (!expectedAudiences.includes(decoded.payload.aud)) {
...

Copy link
Contributor Author

@Dasio Dasio Sep 21, 2023

Choose a reason for hiding this comment

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

In case of GCP IAP, it's string, but I suppose this should be more generic library, or?

Based on https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.3

 In the general case, the "aud" value is an array of case-
   sensitive strings, each containing a StringOrURI value.  In the
   special case when the JWT has one audience

So I think we should allow array

Copy link
Collaborator

Choose a reason for hiding this comment

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

But we are validating only IAP tokens with this lib, right? Or you plan to use it for something else than IAP?

https://cloud.google.com/iap/docs/signed-headers-howto#verifying_the_jwt_payload
Screenshot 2023-09-21 at 16 04 35

Copy link
Contributor Author

@Dasio Dasio Sep 21, 2023

Choose a reason for hiding this comment

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

No. My use case was just to be ready for migration to platform API, where the app would probably need to run for some time in 'dual mode' to allow multiple audiences from IAP.

I thought this was a more generic library and I don't know if it's used only in Kiwi or by someone else. But when I look on readme, I see it's probably just kiwi related, then I don't know why it's public, but that's out of scope of this MR :)

So it's up to you. If you want to allow only single audience from IAP, I'll change it, as we don't need this feature

Copy link
Collaborator

@RobinCsl RobinCsl Sep 21, 2023

Choose a reason for hiding this comment

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

I thought this was a more generic library and I don't know if it's used only in Kiwi or by someone else. But when I look on readme, I see it's probably just kiwi related, then I don't know why it's public, but that's out of scope of this MR :)

Well, there are many things to say about this :)

Given the comment in code and the previous behaviour, I would not support multiple audiences decoded from the JWT token and instead only focus on the middleware's functionality to allow multiple audiences, i.e. validate that the JWT tokens have an audience taken from a provided allow-list.

@RobinCsl
Copy link
Collaborator

One last thing: could you please add a test for multiple audiences passed to the middleware?

@kodiakhq kodiakhq bot merged commit 96dca47 into master Sep 25, 2023
3 checks passed
@kodiakhq kodiakhq bot deleted the multiple-audiencies branch September 25, 2023 07:56
@github-actions
Copy link

🎉 This PR is included in version 2.3.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants