Atlaslog / Field Notes / 3D & Cesium
Field note · 3D & Cesium
Cesium returns 401 because the ion token never took effect
Quick answer
The globe renders but imagery is black and every api.cesium.com request returns 401. Cesium reads Ion.defaultAccessToken once when the Viewer or CesiumWidget is constructed, so assigning it after new Viewer leaves the default resources using an old or undefined token.
Symptom
- An error occurred while accessing https://api.cesium.com/v1/assets/2/endpoint?access_token=undefined: 401 (Unauthorized).
- DeveloperError: Ion token is required to use Cesium's ion services from IonResource.fromAssetId.
- viewer.scene.globe.tilesLoaded never becomes true.
Checklist
- Find the endpoint request in the network panel and inspect the access_token query value.
- Evaluate Cesium.Ion.defaultAccessToken in the console to see the runtime value.
- Print it at the top of the script before any Cesium object is created and compare the two.
- Test the token directly against api.cesium.com to check its assets:read scope and whether it is frozen or deleted.
Fix
Assign Cesium.Ion.defaultAccessToken after the Cesium script loads and before new Cesium.Viewer, or drop ion entirely by passing UrlTemplateImageryProvider and CesiumTerrainProvider.fromUrl so no ion asset is referenced.
Code
An error occurred while accessing https://api.cesium.com/v1/assets/2/endpoint?access_token=undefined: 401 (Unauthorized)
DeveloperError: Ion token is required to use Cesium's ion services.
at IonResource.fromAssetId (IonResource.js:120)<script src="/libs/cesium/1.121/Cesium.js"></script>
<script>
Cesium.Ion.defaultAccessToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...';
var viewer = new Cesium.Viewer('cesiumContainer', {
terrain: Cesium.Terrain.fromWorldTerrain({
requestWaterMask: false,
requestVertexNormals: false
}),
baseLayer: Cesium.ImageryLayer.fromWorldImagery({
style: Cesium.IonImageryProvider.fromAssetId(2)
})
});
</script>
Watch out
- Hardcoding a long-lived master token in the frontend bundle, where it is publicly downloadable; issue short-lived tokens from the backend instead.
- Assuming every 401 is a code bug, when a token without assets:read scope or a deleted token fails identically.
English edition written for Atlaslog from the original Chinese field note. Code is unchanged and runs as-is.
Atlaslog (2026). Cesium returns 401 because the ion token never took effect. https://www.jingweizhi.com/en/cookbook/cesium-ion-token-401.html (accessed 2026-11-03).