diff --git a/modules/carto/src/api/parse-map.ts b/modules/carto/src/api/parse-map.ts index b1fadddae86..5a9ee028e9e 100644 --- a/modules/carto/src/api/parse-map.ts +++ b/modules/carto/src/api/parse-map.ts @@ -19,7 +19,7 @@ import { negateAccessor, getMaxMarkerSize } from './layer-map'; -import {assert} from '../utils'; +import {assert, getAuthFetchOptions} from '../utils'; import {KeplerMapConfig, MapDataset, MapLayerConfig, VisualChannels} from './types'; export type ParseMapResult = { @@ -365,8 +365,8 @@ function createChannelProps( return result; } -function createLoadOptions(accessToken: string) { +function createLoadOptions(accessToken: string | undefined) { return { - loadOptions: {core: {fetch: {headers: {Authorization: `Bearer ${accessToken}`}}}} + loadOptions: {core: {fetch: getAuthFetchOptions(accessToken)}} }; } diff --git a/modules/carto/src/layers/cluster-tile-layer.ts b/modules/carto/src/layers/cluster-tile-layer.ts index 9ff15d16e2a..7f087a49870 100644 --- a/modules/carto/src/layers/cluster-tile-layer.ts +++ b/modules/carto/src/layers/cluster-tile-layer.ts @@ -5,6 +5,7 @@ /* eslint-disable no-shadow */ import {GeoJsonLayer, GeoJsonLayerProps} from '@deck.gl/layers'; +import {getAuthFetchOptions} from '../utils'; import { TileLayer, _Tile2DHeader as Tile2DHeader, @@ -292,7 +293,7 @@ export default class ClusterTileLayer< const tileJSON = this.props.data as TilejsonResult; const scheme = tileJSON && 'scheme' in tileJSON ? tileJSON.scheme : 'quadbin'; return mergeLoadOptions(super.getLoadOptions(), { - fetch: {headers: {Authorization: `Bearer ${tileJSON.accessToken}`}}, + fetch: getAuthFetchOptions(tileJSON.accessToken), cartoSpatialTile: {scheme} }); } diff --git a/modules/carto/src/layers/h3-tile-layer.ts b/modules/carto/src/layers/h3-tile-layer.ts index 049acf67ee2..7a2577c0aa9 100644 --- a/modules/carto/src/layers/h3-tile-layer.ts +++ b/modules/carto/src/layers/h3-tile-layer.ts @@ -3,6 +3,7 @@ // Copyright (c) vis.gl contributors import {CompositeLayer, CompositeLayerProps, DefaultProps} from '@deck.gl/core'; +import {getAuthFetchOptions} from '../utils'; import {H3HexagonLayer, H3HexagonLayerProps} from '@deck.gl/geo-layers'; import H3Tileset2D, {getHexagonResolution} from './h3-tileset-2d'; import SpatialIndexTileLayer, {SpatialIndexTileLayerProps} from './spatial-index-tile-layer'; @@ -49,7 +50,7 @@ export default class H3TileLayer exten getLoadOptions(): any { const tileJSON = this.props.data as TilejsonResult; return mergeLoadOptions(super.getLoadOptions(), { - fetch: {headers: {Authorization: `Bearer ${tileJSON.accessToken}`}}, + fetch: getAuthFetchOptions(tileJSON.accessToken), cartoSpatialTile: {scheme: 'h3'} }); } diff --git a/modules/carto/src/layers/quadbin-tile-layer.ts b/modules/carto/src/layers/quadbin-tile-layer.ts index 3b3bce45bee..db2c306b5a5 100644 --- a/modules/carto/src/layers/quadbin-tile-layer.ts +++ b/modules/carto/src/layers/quadbin-tile-layer.ts @@ -3,6 +3,7 @@ // Copyright (c) vis.gl contributors import {CompositeLayer, CompositeLayerProps, DefaultProps} from '@deck.gl/core'; +import {getAuthFetchOptions} from '../utils'; import QuadbinLayer, {QuadbinLayerProps} from './quadbin-layer'; import QuadbinTileset2D from './quadbin-tileset-2d'; import SpatialIndexTileLayer, {SpatialIndexTileLayerProps} from './spatial-index-tile-layer'; @@ -45,7 +46,7 @@ export default class QuadbinTileLayer< getLoadOptions(): any { const tileJSON = this.props.data as TilejsonResult; return mergeLoadOptions(super.getLoadOptions(), { - fetch: {headers: {Authorization: `Bearer ${tileJSON.accessToken}`}}, + fetch: getAuthFetchOptions(tileJSON.accessToken), cartoSpatialTile: {scheme: 'quadbin'} }); } diff --git a/modules/carto/src/layers/raster-tile-layer.ts b/modules/carto/src/layers/raster-tile-layer.ts index a33a1c23430..b5a614d2bf8 100644 --- a/modules/carto/src/layers/raster-tile-layer.ts +++ b/modules/carto/src/layers/raster-tile-layer.ts @@ -11,6 +11,7 @@ import { LayersList } from '@deck.gl/core'; import RasterLayer, {RasterLayerProps} from './raster-layer'; +import {getAuthFetchOptions} from '../utils'; import QuadbinTileset2D from './quadbin-tileset-2d'; import type {TilejsonResult} from '@carto/api-client'; import {TilejsonPropType, mergeLoadOptions} from './utils'; @@ -66,7 +67,7 @@ export default class RasterTileLayer< getLoadOptions(): any { const tileJSON = this.props.data as TilejsonResult; return mergeLoadOptions(super.getLoadOptions(), { - fetch: {headers: {Authorization: `Bearer ${tileJSON.accessToken}`}} + fetch: getAuthFetchOptions(tileJSON.accessToken) }); } diff --git a/modules/carto/src/layers/vector-tile-layer.ts b/modules/carto/src/layers/vector-tile-layer.ts index b10a6c8a36c..cc6b36ce7cd 100644 --- a/modules/carto/src/layers/vector-tile-layer.ts +++ b/modules/carto/src/layers/vector-tile-layer.ts @@ -24,7 +24,7 @@ import type {TilejsonResult} from '@carto/api-client'; import {TilejsonPropType, mergeLoadOptions, mergeBoundaryData} from './utils'; import {DEFAULT_TILE_SIZE} from '../constants'; import {createPointsFromLines, createPointsFromPolygons} from './label-utils'; -import {createEmptyBinary} from '../utils'; +import {createEmptyBinary, getAuthFetchOptions} from '../utils'; import PointLabelLayer from './point-label-layer'; const MVT_BBOX: GeoBoundingBox = {west: 0, east: 1, south: 0, north: 1}; @@ -89,7 +89,7 @@ export default class VectorTileLayer< getLoadOptions(): any { const tileJSON = this.props.data as TilejsonResult; return mergeLoadOptions(super.getLoadOptions(), { - fetch: {headers: {Authorization: `Bearer ${tileJSON.accessToken}`}}, + fetch: getAuthFetchOptions(tileJSON.accessToken), gis: {format: 'binary'} // Use binary for MVT loading }); } diff --git a/modules/carto/src/utils.ts b/modules/carto/src/utils.ts index cf34dc88376..de1469c2fed 100644 --- a/modules/carto/src/utils.ts +++ b/modules/carto/src/utils.ts @@ -150,3 +150,20 @@ export function copyNumericProps( targetProps[prop].value[targetIndex] = sourceProps[prop].value[sourceIndex]; }); } + +/** + * Fetch options carrying the CARTO Authorization header, or none when no + * access token is present — e.g. a source created with the api-client's + * session auth mode, where tile URLs are same-origin and authenticated by a + * cookie. Emitting `Bearer undefined` would defeat such server-side session + * handling, which engages only when the Authorization header is absent. + */ +export function getAuthFetchOptions(accessToken: string | undefined): { + headers?: Record; + credentials?: RequestCredentials; +} { + if (!accessToken) { + return {credentials: 'same-origin'}; + } + return {headers: {Authorization: `Bearer ${accessToken}`}}; +}