401 INVALID_TOKEN for Cesium World Terrain (asset 1) despite new valid ion token

Hello,

I am running a local TerriaJS-based application (TerriaMap) in development mode (yarn gulp dev, Node v20.19.0). The application loads correctly, but Cesium World Terrain fails with a 401 error.

Console error:

GET https://api.cesium.com/v1/assets/1/endpoint?access_token=...
401 (Unauthorized)
Response: {"code":"INVALID_TOKEN","message":"Invalid access token"}

TerriaJS then switches to EllipsoidTerrainProvider and shows “Terrain Server Not Responding”.

What I have verified:

  • Created a brand-new Cesium ion token.

  • Enabled access to Cesium World Terrain (asset 1).

  • Replaced the token in the application.

  • Restarted the dev server.

  • Hard refreshed the browser (Ctrl+Shift+R).

  • Confirmed in the browser console that:

    window.CESIUM_ION_ACCESS_TOKEN
    
    

    returns exactly the same token string shown in the ion dashboard.

The token used in code and the token returned at runtime are identical.

However, the terrain request still returns:

{"code":"INVALID_TOKEN","message":"Invalid access token"}

Questions:

  1. Under what conditions would a token that matches exactly still return INVALID_TOKEN?

  2. Is there any server-side delay or validation state after generating a new token?

  3. Is there a recommended direct API call to validate whether a token is active and authorized for asset 1?

  4. Could TerriaJS be modifying the request in a way that affects token validation?

Any guidance on isolating whether this is an ion token issue, asset permission issue, or integration issue would be helpful.

Hi,

Under what conditions would a token that matches exactly still return INVALID_TOKEN?

This shouldn’t happen unless you specified an allowed urls value in the token. Can you verify that it isn’t set for this token?

Is there any server-side delay or validation state after generating a new token?

There isn’t any delay and it should work instantly

Is there a recommended direct API call to validate whether a token is active and authorized for asset 1?

The endpoint route should load if you have the correct scopes on the token. Can you double check which scopes you have provided? You can also try getting asset metadata to see if you have the correct scope v1/assets/{assetId}

Could TerriaJS be modifying the request in a way that affects token validation?

While that may be possible and I can’t say for sure, it seems unlikely. Can you also double check the token got copied correctly

Hello @Ankit_Trehan,

Thank you for the guidance. I have now verified the following in detail:


1- Allowed URLs Restriction

The token does not have any Allowed URLs restriction configured.

In the Cesium ion dashboard:

  • Allowed URLs: Empty

  • Assets: All assets enabled

  • Scopes: see below

So there is no domain restriction that could invalidate requests from http://localhost.


2- Token Scopes

The token has the following scopes enabled:

  • :check_mark: assets:read

  • :check_mark: geocode

  • :check_mark: profile:read

Cesium World Terrain (asset 1) requires assets:read, which is enabled.


3- Direct Endpoint Validation (Manual API Test)

To eliminate TerriaJS as a variable, I tested the token directly against the ion API.

Test 1 – Asset metadata

GET https://api.cesium.com/v1/assets/1
Authorization: Bearer <TOKEN>

Using curl:

curl -H "Authorization: Bearer <TOKEN>" \
https://api.cesium.com/v1/assets/1

Result:

  • :cross_mark: Returns 401

  • Response: {“code”:“INVALID_TOKEN”,“message”:“Invalid access token”}


Test 2 – Endpoint route (same as TerriaJS request)

curl https://api.cesium.com/v1/assets/1/endpoint?access_token=<TOKEN>

Result:

  • :cross_mark: Returns 401

  • Response: {“code”:“INVALID_TOKEN”,“message”:“Invalid access token”}


This confirms:

  • The issue is reproducible outside TerriaJS

  • It is not related to initialization order

  • It is not a caching issue

  • It is not a browser-side issue


4- Runtime Verification

In the browser console:

window.CESIUM_ION_ACCESS_TOKEN

returns exactly the same token string shown in the ion dashboard.

Additionally:

window.CESIUM_ION_ACCESS_TOKEN === "<TOKEN>"

returns true.

There is no whitespace, no truncation, and no encoding issue.


5- Initialization Order

The token is set before Terria loads.

In index.ejs:

<script>
  window.CESIUM_ION_ACCESS_TOKEN = "<TOKEN>";
</script>

In config.json:

{
  "configParameters": {
    "cesiumIonAccessToken": "<TOKEN>"
  }
}

So both mechanisms are providing the same value.


6- Observations

Since:

  • The token matches exactly.

  • Allowed URLs are not restricted.

  • Correct scopes are enabled.

  • Direct API calls fail with INVALID_TOKEN.

  • There is no propagation delay.

  • Multiple newly-created tokens produce the same result.

This suggests one of the following:

  1. The token is being marked invalid server-side immediately after creation.

  2. There is an account-level issue preventing token validation.

  3. There is an ion-side validation issue specific to asset 1.


7- Clarification Request

Could you confirm:

  1. Is there any known issue currently affecting token validation for asset 1?

  2. Is there any account-level flag that could invalidate all newly created tokens?

  3. Is there a recommended endpoint specifically to validate token health independent of assets?

  4. Could you check server-side logs for this token ID to see why it is being rejected as INVALID_TOKEN?

Since direct calls to /v1/assets/1 fail outside TerriaJS, this appears to be an ion-side token validation issue rather than an integration problem.

Thank you for your assistance.
Hossein

Hi,

There aren’t any issues that should affect asset 1 specifically. Unless the account was blocked for excessive usage, there shouldn’t be an account level flag that prevents you from accessing the asset either.

Would you be able to send us the token you are using in the private thread so that we can take a look at what its scopes and permissions look like? That will be very helpful to debug the issue

Thanks,
Ankit

Hi Ankit,

Thank you for your response and for offering to investigate.

As requested, I am sharing the token below via this private thread for
inspection:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJjMTM5Zjc3My03NDdjLTQ4NzUtODBjNS04YjY0NDQxODFmMjMiLCJpZCI6MzgwNzA0LCJpYXQiOjE3NzA5NTk3MDl9.AOtjQTUyzC1EdodGacezlNb5-OQlSMxM_cC-9M65goU

Context summary: