Skip to content

Runs API failing with 403 when using access token with broad scopes (not run specific) #1477

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

Closed
felix-quotez opened this issue Nov 17, 2024 · 4 comments

Comments

@felix-quotez
Copy link

felix-quotez commented Nov 17, 2024

Provide environment information

"@trigger.dev/react-hooks": "^3.2.0",
"@trigger.dev/sdk": "^3.1.2",
"@trigger.dev/build": "^3.1.2",

Describe the bug

Front-end API access returns 403 for access token with broad scopes.

Possibly introduce by #1402.

Reproduction repo

http://sorry.out.of.time.com

To reproduce

Steps to repro:

Create a token as documented here

const publicToken = await auth.createPublicToken({
  scopes: {
    read: {
      runs: true,
    },
  },
});

Paste the generate token to the JWT debugger and observe that the scopes array in the decoded payload is empty.
When making a request with this token, the response from "https://api.trigger.dev/api/v3/runs/" is 403.

Analysis from looking at the code:
In https://github.com/triggerdotdev/trigger.dev/blob/332854bbcbc53703e64e9a5dd71944deabe51f2b/packages/trigger-sdk/src/v3/auth.ts

function flattenScopes(permissions: PublicTokenPermissions): string[] {
  const flattenedPermissions: string[] = [];

  for (const [action, properties] of Object.entries(permissions)) {
    if (properties) {
      if (typeof properties === "boolean" && properties) {
        flattenedPermissions.push(action);
      } else if (typeof properties === "object") {
        for (const [property, value] of Object.entries(properties)) {
          if (Array.isArray(value)) {
            for (const item of value) {
              flattenedPermissions.push(`${action}:${property}:${item}`);
            }
          } else if (typeof value === "string") {
            flattenedPermissions.push(`${action}:${property}:${value}`);
          }
        }
      }
    }
  }

  return flattenedPermissions;
}

The check

if (typeof properties === "boolean" && properties) {

seems incorrect. The action is 'read' but 'properties' is not a boolean, it is'{ runs: true }'.

For what it's worth, when forcing TS to accept an object in the shape that "flattenScopes" expects

return auth.createPublicToken({
scopes: {
     read: true,
} as any)

the JWT claims have the expected (?) shape but the API still gives me 403.

Additional information

No response

@felix-quotez
Copy link
Author

An ugly workaround to allow reading all runs

import { apiClientManager } from '@trigger.dev/core/v3'
import { generateJWT } from '@trigger.dev/core/v3'

export async function getTriggerDevAccessToken() {
  const apiClient = apiClientManager.clientOrThrow()

  const claims = await apiClient.generateJWTClaims()

  return generateJWT({
    secretKey: apiClient.accessToken,
    payload: {
      ...claims,
      scopes: ['read:runs'],
    },
  })
}

@ericallam
Copy link
Member

This has been fixed in #1470, which should be going live this week

@felix-quotez
Copy link
Author

Great, thanks a lot!

@felix-quotez
Copy link
Author

Fix verified with 3.2.1. Thank you! Closing.

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

No branches or pull requests

2 participants