Using this guide <https://www.gooddata.com/docs/cl...
# gooddata-cloud
o
Using this guide https://www.gooddata.com/docs/cloud/manage-organization/jwt-access-token/jwt-javascript-example/ we created our GD JWK. After embedding the GD iframe into our React app which uses JWT we are getting 401 errors in developer console and this message on screen
<http://auth.cloud.gooddata.com|auth.cloud.gooddata.com> refused to connect.
j
Hi Oscar, The issue probably happens because authentication must be completed before loading the GoodData iframe. If not, the iframe tries to show the login page, which is blocked for security reasons. To fix this, you need to authenticate using your JWT first (outside of the iframe), and only then load the dashboard. Once authenticated, the iframe should display correctly without errors.
o
@Julius Kos our users have authenticated within our app already before navigating to that page with the iFrame
m
Hi Oscar, thank you for this clarification - In this case, could you please generate a .HAR file and then reproduce the issue once again and send us over the generated file? Thank you!
o
@Michael Ullock attached
m
Hi Oscar, the issue may stem from an incorrect setup between the authentication (Auth0) and the React application. Could you explain how you have configured Auth0 authentication in your app? Please share the relevant settings. It appears that the iframe is being redirected to your application instead of the GoodData dashboard.
o
We are not using Auth0, our react app has it's own authentication mechanism and the token is created with this code in node.js
Copy code
const jwt = require('jsonwebtoken');
    ...
    const user = {
      _id: u._id,
      company,
      email: u.email,
      name: u.name,
      phone: u.phone,
      photo: u.photo,
      username: u.username,
      appId,
      ...
    };

    const token = jwt.sign(user, process.env.JWT_STRATEGY_SECRET, {
      expiresIn,
    });
    ...
Before we signed up with GD, we were only told that if we were using JWT then we have to use the GD JWK. no mention of Auth0 nor OAuth.
j
Hi Oscar, no worries, that’s correct. The error quote might be a bit misleading in this case. May I ask you for some example user who uses the JWT authentication? I would like to check our logs. So far I don’t see there any JWT login attempt. Just standard OIDC traffic.
I only saw this log from yesterday:
Copy code
"msg":"Stored JWT token cannot be decoded: Cannot read ID Token from the session: JWT (sub=auth0|6706eb6425c08a6859d3812a) has expired.., cause: null","orgId":"nwgtqc8odk"}
Could you please double-check that?
otherwise, I don’t see any JWT log since then…
o
are we supposed to login to the GD JWK? or register our users into the GD JWK?
or do we replace our
process.env.JWT_STRATEGY_SECRET
with the GD JWK private or public key?
j
You don’t log in to the GD JWK or register users there. The JWK is only a public key that GoodData uses to verify the JWTs your app creates. You also don’t replace your
process.env.JWT_STRATEGY_SECRET
with anything from GoodData. You keep using your own private key to sign JWTs, and GoodData uses the uploaded public JWK to verify them. Your app fully controls user authentication and JWT signing — the JWK is only for verification on GoodData’s side.
o
thanks for confirming that. So, this is what we have: 1. user login to our site. gets a JWT 2. user navigates to different pages as an authenticated user. 3. when user navigates to the page with the embedded GD iFrame we get the 401 error along with
*<http://auth.cloud.gooddata.com|auth.cloud.gooddata.com>* refused to connect.
message on the page
j
Thank you. One more question - have you set CORS and CSP policy on your domain? https://www.gooddata.com/docs/cloud/manage-organization/set-up-cors-for-organization/
hm, but not sure if that is the issue (pls double-check), while checking logs, I can see your attempt from an hour ago:
Copy code
"Stored JWT token cannot be decoded: Cannot read ID Token from the session: JWT (sub=auth0|6706eb6425c08a6859d3812a) has expired..,
However, that error quote would make sense as there is no valid session for a user.
Could you please also check if the JWK was uploaded correctly? As per our documentation:
You can confirm the JWK was uploaded correctly by making a GET call to the same API endpoint. Your JWK should be saved as:
Copy code
{
  "data": {
    "attributes": {
      "content": {
        "kty": "RSA",
        "alg": "RS256",
        "use": "sig",
        "kid": "67C2BC3D-32E4-4C8C-93EF-9B03F0E65A3A",
        "x5t": "oLe3EKODu72OtVftIu8_WGaPWk8",
        "x5c": [
          "MIICujCCAaKgAwIBAgIECI8fsTANBgkqhkiG9w0BAQsFADAfMR0wGwYDVQQDExR0ZXN0LWFsZXgucmVhY2g1Lm5ldDAeFw0yMDA3MjkwOTM0MjlaFw0yMjAyMTcxNDIwMzNaMB8xHTAbBgNVBAMTFHRlc3QtYWxleC5yZWFjaDUubmV0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlzRszUeQ4WiSqvmYxMP10ngm8ALIoUwMH7Oa8vrZgD5pqalPjetPAxeVcAv2gTyDlOwtB0fGvlQo6n78pd9pTbgrzUjhmFuYN6OCfT6eN/2wu0LmwryFS2mbh7/1DTiKd2tZaRalskPECXTKkeks85HVqanB0860BYlGvQvfgrvhCWXXFJJeXvNwYNFYdDdrFQhoeOAEvRDKg9DdHZf6XzSR6Qk3w51FKn2b7imen/G52itD/kIen1hqqB2Jwt9SWyX5MSGySY2QwC18F6Dfs8L+t0mwCo6grGW9264Z5vlO0PWssEqGIX/ez6nk1ZdHXhoXwJ0W+6QzeQlUN8jNoQIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQAETbMWro4HI4ZuqtnjMZrgEOpx6WhAtxpMx5XFPVWbdp/DpPySotoWbbD6qCtYc34E+ec7mH7aHVap+Gl2IyeSHTht4FXfF9q/1Oj/fis/4DDi1iq00rJsU18D71mZ9FGWCWlO1nhW1KSTGbRJ3E0wSrNabcvaXcwEHokR3zm+xfRWjtbrq2hQ19R16xyOLVy4zrF95QxP4UN+Cvm8nmYur6bSqv+gCMvDsl+O/gtRHGgpUukHEJwnee1R3+1aIv+9zOF3HaaUC5neOLBFITGmeXgi8G2IhbG+JoXh/GUkb66TZUlUAM3qXYNL9Nf+2MQ7nAPTXcxlmImFUUrnv0c3"
        ],
        "e": "AQAB",
        "n": "wAwTHQIRVkX4m6lI0ayO1b7FnR4hgH9KFQJPHO7i11zJ6exhs7nzS4WGTlOMzM_j17O3zcBEYfe1P65rhikRhRuYU3cBmqQGxTQEZcTqmOSZxjB7TPukp7R57IvbmYuHFZjxqSQQpazopvCCMHO5OECilT_Md_xuZtdZDehOYNwZM880kN0KKtGFDXDQzC110uk0R_mVatuPY1ZIe0lYnfkokKqfWma849zpcpJE5MiIIxTFsFANsRW3he72EodoDMEhYZnUOQ4dGk_t3OiY-NgtRKtI1vW5T-rsZ0Tl3oRqJmXPeE5TP8bC3n-nm_SJPtDyc2Q-8CO1EITIZR8Ikw"
      }
    },
    "id": "jwk-1",
    "type": "jwk"
  }
}
If you still won’t be able to make the JWT authentication flow work, let me know, I will consult the case with our engineers.
o
Here's our result:
Copy code
{
  "data": {
    "id": "clockworkDeliveryGoodDataKeyId",
    "type": "jwk",
    "attributes": {
      "content": {
        "kty": "RSA",
        "alg": "RS256",
        "use": "sig",
        "x5c": [
          "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"
        ],
        "n": "ojVDY-mibfx5sYxcyoX2ruj3eMHCTzzSf2t3sYPa3mfXc8hZo8yYYXjYaL2HdgBNTjaj3jw3KxyAcb4BQD_h32EYg-4fNYM4grV3kaG0hLY9WdqtQpcamgfJCsGCx0eLPLXbOyW9iNqtYuBiYtHJA7dNtn82IKW_xYciXtaNU3v_ATBtu8VR46qqK4hgC4G9BefGTQd7BrJZRprd7hChH57MTnkhwdvekCmiFwt3BZ3-uZh0f7u-GhegHqjkSaERPhdHRaBuQe90SDgY-Skr5GsnT4MyhvZwO8p69GsN4QPzXRUMCsKam1srzWAwSwJ6zw4aHkRvOpbfMwrkkeG6UoDc1bBlv82HowdCT7WX--0lUFTHfmyDJns7qvaHSyFLnUF3zZCNqOUdm9Glh7R979ZbmdiBehCVOskEDVGbsLNAPj3on5dynx9FoAj3RkWBKDsfM6h4fa3AGl8C3rET1ECsBwAm89WYvrPX7WBldT-DFV4Jx852nJjosBPl-QHkKBcQJ7ubBLR-s5FJHz7q0E2HNhH4GOMpSlwvTvTTV-t1QUwUr0vTsatHPGsUsfhW_us59fvr4SjBX6Dtf9osMRKCX0ipintV5TjgSUUgvO2lSJG135Tzr8NsLBRhT2XPfZe0EpKMDZLH0MTxg9eNDbqgquo-uGkRPzxg0tmc_K0",
        "e": "AQAB",
        "kid": "clockworkDeliveryGoodDataKeyId",
        "x5t": "_JR9NVaOWKkSSXoqxXdKP86yfvU"
      }
    }
  },
  "links": {
    "self": "<https://clockworkdelivery.cloud.gooddata.com/api/v1/entities/jwks/clockworkDeliveryGoodDataKeyId>"
  }
}
after allowing CORS, we now have a different message:
j
may I know what do you see in Console? is there any traceID or any other error quote?
o
we are getting a bunch of 401s,
Uncaught (in promise) O: No session or session expired
and
Refused to frame '<https://auth.cloud.gooddata.com/>' because an ancestor violates the following Content Security Policy directive: "frame-ancestors 'none'".
j
interesting, have you tried to set the CSP as well?
o
the
frame-ancestor
error comes from
<https://auth.cloud.gooddata.com/>
btw, the page is back to the previous display
j
Okay, thank you for all the details and your patience. I will gather now all the information and pass the case to or L2 Technical Team. One of the team members will contact you as soon as possible.
j
Thanks @Julius Kos This is the penultimate step before we launch our solution to our users (after 4.5 months of development). Whatever you can do to help us expedite will be huge!
j
Hi @Oscar Yu @John K Chang, could you please check how the iframe is embedded into your app? Based on the error you are experiencing it looks like the iframe is resulting in default auth flow which is OIDC. When using JWT for iframe authentication the embedded iframe url should contain
?apiTokenAuthentication=true
query parameter otherwise the auth falls back to default OIDC flow. https://www.gooddata.com/docs/cloud/embed-visualizations/iframes/embed-dashboard-via-iframe/#example-of-authentication-using-injected-jwt Could you please verify this?
o
checking...
no more errors in the developer console but the iframe is just blank white screen
ok. now back to 401 errors.
is there a specific attribute in the JWT that we have to include?
@Jan Kos @Julius Kos any updates or hints from the server logs?
j
Hi, there might be an issue with the token itself if its resulting in this page. if you try to use the generated token as a authorization bearer in an API call. does it succeed?
If yes, could you please share the code snippet how is the iframe implemented and how you are passing JWT to it?
o
looks like we need to add the
sub
attribute into the token... coding...
@Jan Kos are custom attributes allowed? when i used on online JWT decoder, it gave us this: Header:
Copy code
{
  "alg": "HS256",
  "typ": "JWT"
}
Payload:
Copy code
{
  "_id": "dc8ce542daf63e7f14a5b32",
  "sub": "dc8ce542daf63e7f14a5b32",
  "iss": "portal-api",
  "iat": 1746553538,
  "active": true,
  "cntryCd": "+1",
  "company": {
    "_id": "3e12119d74xxx",
    "config": "c3e32b279xxx",
    "name": "WallMaltz",
    "businessType": "shipper",
    "parentId": "dc8ce542daf63e7f14a5b41",
    "utcOffset": "-8"
  },
  "created": "2019-02-20T00:41:41.414Z",
  "email": "angel@angels.com",
  "isSuper": false,
  "name": "La Angels",
  "phone": "+17025550001",
  "roles": [
    {
      "isDefault": false,
      "_id": "xxx4f172c035d",
      "company": "xxx4624f17xxx",
      "created": "2019-01-15T17:02:09.915Z",
      "roleCd": "admin",
      "__v": 125
    }
  ],
  "username": "angel@angels.com",
  "appId": "com.google.firefox",
  "identifyKey": "36524c3e-xxxx-1724babbc0b3",
  "lastLoginDt": "2022-11-04T15:23:49.046Z",
  "exp": 1747763138
}
here's the React page
@Jan Kos @Julius Kos Is there a secure way we can send you the CURL with the token?
We are getting this when using curl
Copy code
HTTP/1.1 401 Unauthorized
Date: Tue, 06 May 2025 19:03:24 GMT
Content-Length: 0
Connection: close
Vary: Origin, Access-Control-Request-Method, Access-Control-Request-Headers
WWW-Authenticate: Bearer error="invalid_token", error_description="The JWT contains invalid claims.", error_uri="<https://tools.ietf.org/html/rfc6750#section-3.1>"
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Content-Type-Options: nosniff
Strict-Transport-Security: max-age=63072000; includeSubDomains
X-XSS-Protection: 0
Referrer-Policy: no-referrer
j
I checked the logs I can see the same error message (we don’t have more verbose error description unfortunately)
Copy code
"action":"login","exc":"...JwtVerificationException: The JWT contains invalid claims.
However this is a general error and its thrown when JWT validation fails. Mandatory claims that should be included in the token are
"name", "sub", "iat", "exp"
, additional claims (attributes) shouldn’t cause an issue as long as mandatory are present. I noticed in decoded token you provided -
"alg": "HS256"
algorithm, but our supported algorithms are
RS256, RS384, RS512
that could be a problem. Also missing
kid
in JWT might cause an issue as the attributes which key should be used to verify JWT.
If you’d like to share with us sensitive information, you can encrypt the file or text with our GoodData PGP public key
additionally I found in the logs
Copy code
"action":"login","authenticationMethod":"JWT","exc":"....Exception: An error occurred while attempting to decode the Jwt
and
Copy code
Caused by: ...: Signed JWT rejected: Another algorithm expected, or no matching key(s) found
which supports the above
o
we are working on switching to the new algorithm
@Jan Kos we are now sending RS256 token, which decoded to:
Copy code
{
  "alg": "RS256",
  "typ": "JWT",
  "kid": "xxxxxxxGoodDataKeyId"
}
and payload:
Copy code
{
  "sub": "iiiiiiiiiii",
  "id": "iiiiiiiiiii",
  "name": "CWAdmin",
  "company": "xxxxxxxxxx",
  "iat": 1746727676,
  "jti": "3acd9fc7-f45b-4f3f-a534-5e411203ac5a",
  "exp": 1746814076
}
and we are now getting a 404 error when calling the profile endpoint
Copy code
{
  "title": "Not Found",
  "status": 404,
  "detail": "The requested endpoint does not exist or you do not have permission to access it.",
  "traceId": "d11df71b868383a21b8b6fd6b74414aa"
}
j
Hi @Oscar Yu under the traceId, I can see in our logs:
Copy code
{
  "traceId": "d11df71b868383a21b8b6fd6b74414aa",
  "msg": "Not Found",
  "exc": "No user found for API ID"
}
This error indicates that user for the given token wasn’t found on the backend. Could you please double-check that appropriate user exists in your GD Cloud organization and that
sub
claim is correctly populated with
userId
from your GD cloud organization?
o
Thanks @Jan Kos and @Julius Kos. We are now able to see the embedded dashboard. One final question, is it possible to access the additional claims from within the workspace? Like if we want to pass the currently selected department for the same user to the GD workspace?
j
Hi @Oscar Yu I’m glad that you were able to resolve this.. Using additional claims is currently not supported in JWT authentication unfortunately.
o
How about iframe parameters?
j
please find supported iframe url parameters here.. And could you please elaborate on what is the use case for accessing additional claims? What should be the end result of it?
o
Thanks. We will dig into it