LogoLogo
HomeAcademyLoginTry for free
  • Welcome
  • What's new
    • Q2 2025
    • Q1 2025
    • Q4 2024
    • Q3 2024
    • Q2 2024
    • Q1 2024
    • Q4 2023
    • Q3 2023
    • Q2 2023
    • Q1 2023
    • Q4 2022
    • Q3 2022
  • FAQs
    • Accounts
    • Migration to the new platform
    • User & organization setup
    • General
    • Builder
    • Workflows
    • Data Observatory
    • Analytics Toolbox
    • Development Tools
    • Deployment Options
    • CARTO Basemaps
    • CARTO for Education
    • Support Packages
    • Security and Compliance
  • Getting started
    • What is CARTO?
    • Quickstart guides
      • Connecting to your data
      • Creating your first map
      • Creating your first workflow
      • Developing your first application
    • CARTO Academy
  • CARTO User Manual
    • Overview
      • Creating your CARTO organization
      • CARTO Cloud Regions
      • CARTO Workspace overview
    • Maps
      • Data sources
        • Simple features
        • Spatial Indexes
        • Pre-generated tilesets
        • Rasters
        • Defining source spatial data
        • Managing data freshness
        • Changing data source location
      • Layers
        • Point
          • Grid point aggregation
          • H3 point aggregation
          • Heatmap point aggregation
          • Cluster point aggregation
        • Polygon
        • Line
        • Grid
        • H3
        • Raster
        • Zoom to layer
      • Widgets
        • Formula widget
        • Category widget
        • Pie widget
        • Histogram widget
        • Range widget
        • Time Series widget
        • Table widget
      • SQL Parameters
        • Date parameter
        • Text parameter
        • Numeric parameter
        • Publishing SQL parameters
      • Interactions
      • Legend
      • Basemaps
        • Basemap selector
      • AI Agents
      • SQL analyses
      • Map view modes
      • Map description
      • Feature selection tool
      • Search locations
      • Measure distances
      • Exporting data
      • Download PDF reports
      • Managing maps
      • Publishing and sharing maps
        • Map settings for viewers
        • Map preview for editors
        • Collaborative maps
        • Embedding maps
        • URL parameters
      • Performance considerations
    • Workflows
      • Workflow canvas
      • Results panel
      • Components
        • Aggregation
        • Custom
        • Data Enrichment
        • Data Preparation
        • Generative AI
        • Input / Output
        • Joins
        • Parsers
        • Raster Operations
        • Spatial Accessors
        • Spatial Analysis
        • Spatial Constructors
        • Spatial Indexes
        • Spatial Operations
        • Statistics
        • Tileset Creation
        • BigQuery ML
        • Snowflake ML
        • Google Earth Engine
        • Google Environment APIs
        • Telco Signal Propagation Models
      • Data Sources
      • Scheduling workflows
      • Sharing workflows
      • Using variables in workflows
      • Executing workflows via API
      • Temporary data in Workflows
      • Extension Packages
      • Managing workflows
      • Workflows best practices
    • Data Explorer
      • Creating a map from your data
      • Importing data
        • Importing rasters
      • Geocoding data
      • Optimizing your data
    • Data Observatory
      • Terminology
      • Browsing the Spatial Data Catalog
      • Subscribing to public and premium datasets
      • Accessing free data samples
      • Managing your subscriptions
      • Accessing your subscriptions from your data warehouse
        • Access data in BigQuery
        • Access data in Snowflake
        • Access data in Databricks
        • Access data in Redshift
        • Access data in PostgreSQL
    • Connections
      • Google BigQuery
      • Snowflake
      • Databricks
      • Amazon Redshift
      • PostgreSQL
      • CARTO Data Warehouse
      • Sharing connections
      • Deleting a connection
      • Required permissions
      • IP whitelisting
      • Customer data responsibilities
    • Applications
    • Settings
      • Understanding your organization quotas
      • Activity Data
        • Activity Data Reference
        • Activity Data Examples
        • Activity Data Changelog
      • Users and Groups
        • Inviting users to your organization
        • Managing user roles
        • Deleting users
        • SSO
        • Groups
        • Mapping groups to user roles
      • CARTO Support Access
      • Customizations
        • Customizing appearance and branding
        • Configuring custom color palettes
        • Configuring your organization basemaps
        • Enabling AI Agents
      • Advanced Settings
        • Managing applications
        • Configuring S3 Bucket for Redshift Imports
        • Configuring OAuth connections to Snowflake
        • Configuring OAuth U2M connections to Databricks
        • Configuring S3 Bucket integration for RDS for PostgreSQL Exports in Builder
        • Configuring Workload Identity Federation for BigQuery
      • Data Observatory
      • Deleting your organization
    • Developers
      • Managing Credentials
        • API Base URL
        • API Access Tokens
        • SPA OAuth Clients
        • M2M OAuth Clients
      • Named Sources
  • Data and Analysis
    • Analytics Toolbox Overview
    • Analytics Toolbox for BigQuery
      • Getting access
        • Projects maintained by CARTO in different BigQuery regions
        • Manual installation in your own project
        • Installation in a Google Cloud VPC
        • Core module
      • Key concepts
        • Tilesets
        • Spatial indexes
      • SQL Reference
        • accessors
        • clustering
        • constructors
        • cpg
        • data
        • http_request
        • import
        • geohash
        • h3
        • lds
        • measurements
        • placekey
        • processing
        • quadbin
        • random
        • raster
        • retail
        • routing
        • s2
        • statistics
        • telco
        • tiler
        • transformations
      • Guides
        • Running queries from Builder
        • Working with Raster data
      • Release notes
      • About Analytics Toolbox regions
    • Analytics Toolbox for Snowflake
      • Getting access
        • Native App from Snowflake's Marketplace
        • Manual installation
      • Key concepts
        • Spatial indexes
        • Tilesets
      • SQL Reference
        • accessors
        • clustering
        • constructors
        • data
        • http_request
        • import
        • h3
        • lds
        • measurements
        • placekey
        • processing
        • quadbin
        • random
        • raster
        • retail
        • s2
        • statistics
        • tiler
        • transformations
      • Guides
        • Running queries from Builder
        • Working with Raster data
      • Release Notes
    • Analytics Toolbox for Databricks
      • Getting access
        • Personal (former Single User) cluster
        • Standard (former Shared) cluster
      • Reference
        • lds
        • tiler
      • Guides
      • Release Notes
    • Analytics Toolbox for Redshift
      • Getting access
        • Manual installation in your database
        • Installation in an Amazon Web Services VPC
        • Core version
      • Key concepts
        • Tilesets
        • Spatial indexes
      • SQL Reference
        • clustering
        • constructors
        • data
        • http_request
        • import
        • lds
        • placekey
        • processing
        • quadbin
        • random
        • s2
        • statistics
        • tiler
        • transformations
      • Guides
        • Running queries from Builder
      • Release Notes
    • Analytics Toolbox for PostgreSQL
      • Getting access
        • Manual installation
        • Core version
      • Key concepts
        • Tilesets
        • Spatial Indexes
      • SQL Reference
        • h3
        • quadbin
        • tiler
      • Guides
        • Creating spatial index tilesets
        • Running queries from Builder
      • Release Notes
    • CARTO + Python
      • Installation
      • Authentication Methods
      • Visualizing Data
      • Working with Data
        • How to work with your data in the CARTO Data Warehouse
        • How to access your Data Observatory subscriptions
        • How to access CARTO's Analytics Toolbox for BigQuery and create visualizations via Python notebooks
        • How to access CARTO’s Analytics Toolbox for Snowflake and create visualizations via Python notebooks
        • How to visualize data from Databricks
      • Reference
    • CARTO QGIS Plugin
  • CARTO for Developers
    • Overview
    • Key concepts
      • Architecture
      • Libraries and APIs
      • Authentication methods
        • API Access Tokens
        • OAuth Access Tokens
        • OAuth Clients
      • Connections
      • Data sources
      • Visualization with deck.gl
        • Basemaps
          • CARTO Basemap
          • Google Maps
            • Examples
              • Gallery
              • Getting Started
              • Basic Examples
                • Hello World
                • BigQuery Tileset Layer
                • Data Observatory Tileset Layer
              • Advanced Examples
                • Arc Layer
                • Extrusion
                • Trips Layer
            • What's New
          • Amazon Location
            • Examples
              • Hello World
              • CartoLayer
            • What's New
        • Rapid Map Prototyping
      • Charts and widgets
      • Filtering and interactivity
      • Summary
    • Quickstart
      • Make your first API call
      • Visualize your first dataset
      • Create your first widget
    • Guides
      • Build a public application
      • Build a private application
      • Build a private application using SSO
      • Visualize massive datasets
      • Integrate CARTO in your existing application
      • Use Boundaries in your application
      • Avoid exposing SQL queries with Named Sources
      • Managing cache in your CARTO applications
    • Reference
      • Deck (@deck.gl reference)
      • Data Sources
        • vectorTableSource
        • vectorQuerySource
        • vectorTilesetSource
        • h3TableSource
        • h3QuerySource
        • h3TilesetSource
        • quadbinTableSource
        • quadbinQuerySource
        • quadbinTilesetSource
        • rasterSource
        • boundaryTableSource
        • boundaryQuerySource
      • Layers (@deck.gl/carto)
      • Widgets
        • Data Sources
        • Server-side vs. client-side
        • Models
          • getFormula
          • getCategories
          • getHistogram
          • getRange
          • getScatter
          • getTimeSeries
          • getTable
      • Filters
        • Column filters
        • Spatial filters
      • CARTO APIs Reference
    • Release Notes
    • Examples
    • CARTO for React
      • Guides
        • Getting Started
        • Views
        • Data Sources
        • Layers
        • Widgets
        • Authentication and Authorization
        • Basemaps
        • Look and Feel
        • Query Parameters
        • Code Generator
        • Sample Applications
        • Deployment
        • Upgrade Guide
      • Examples
      • Library Reference
        • Introduction
        • API
        • Auth
        • Basemaps
        • Core
        • Redux
        • UI
        • Widgets
      • Release Notes
  • CARTO Self-Hosted
    • Overview
    • Key concepts
      • Architecture
      • Deployment requirements
    • Quickstarts
      • Single VM deployment (Kots)
      • Orchestrated container deployment (Kots)
      • Advanced Orchestrated container deployment (Helm)
    • Guides
      • Guides (Kots)
        • Configure your own buckets
        • Configure an external in-memory cache
        • Enable Google Basemaps
        • Enable the CARTO Data Warehouse
        • Configure an external proxy
        • Enable BigQuery OAuth connections
        • Configure Single Sign-On (SSO)
        • Use Workload Identity in GCP
        • High availability configuration for CARTO Self-hosted
        • Configure your custom service account
      • Guides (Helm)
        • Configure your own buckets (Helm)
        • Configure an external in-memory cache (Helm)
        • Enable Google Basemaps (Helm)
        • Enable the CARTO Data Warehouse (Helm)
        • Configure an external proxy (Helm)
        • Enable BigQuery OAuth connections (Helm)
        • Configure Single Sign-On (SSO) (Helm)
        • Use Workload Identity in GCP (Helm)
        • Use EKS Pod Identity in AWS (Helm)
        • Enable Redshift imports (Helm)
        • Migrating CARTO Self-hosted installation to an external database (Helm)
        • Advanced customizations (Helm)
        • Configure your custom service account (Helm)
    • Maintenance
      • Maintenance (Kots)
        • Updates
        • Backups
        • Uninstall
        • Rotating keys
        • Monitoring
        • Change the Admin Console password
      • Maintenance (Helm)
        • Monitoring (Helm)
        • Rotating keys (Helm)
        • Uninstall (Helm)
        • Backups (Helm)
        • Updates (Helm)
    • Support
      • Get debug information for Support (Kots)
      • Get debug information for Support (Helm)
    • CARTO Self-hosted Legacy
      • Key concepts
        • Architecture
        • Deployment requirements
      • Quickstarts
        • Single VM deployment (docker-compose)
      • Guides
        • Configure your own buckets
        • Configure an external in-memory cache
        • Enable Google Basemaps
        • Enable the CARTO Data Warehouse
        • Configure an external proxy
        • Enable BigQuery OAuth connections
        • Configure Single Sign-On (SSO)
        • Enable Redshift imports
        • Configure your custom service account
        • Advanced customizations
        • Migrating CARTO Self-Hosted installation to an external database
      • Maintenance
        • Updates
        • Backups
        • Uninstall
        • Rotating keys
        • Monitoring
      • Support
    • Release Notes
  • CARTO Native App for Snowflake Containers
    • Deploying CARTO using Snowflake Container Services
  • Get Help
    • Legal & Compliance
    • Previous libraries and components
    • Migrating your content to the new CARTO platform
Powered by GitBook
On this page
  • Overview
  • Scaffolding your backend
  • Creating a M2M OAuth Client in CARTO
  • Coding the endpoint
  • Frontend side integration
  • What's next?

Was this helpful?

Export as PDF
  1. CARTO for Developers
  2. Guides

Integrate CARTO in your existing application

Learn how to securely embed CARTO into your existing architecture providing fine-grained data access

PreviousVisualize massive datasetsNextUse Boundaries in your application

Last updated 1 year ago

Was this helpful?

When you build a solution from scratch using CARTO you can choose between the three different to secure your application. However, in many other cases the starting point is an existing application with its own login system where you want to add a geospatial component, such as a map visualization.

In this guide you will learn how to integrate CARTO with an existing application that has its own login system, implementing the machine-to-machine authentication in order to provide fine-grained data access to the end users.

Overview

In this guide, the ACME company has decided to add maps to their existing application and CARTO will be the platform used for it. They have two important requirements:

  • ACME wants to keep its own login system.

  • The maps will show different data based on the user, in this case, based on the user's group.

With this in mind, we are going to develop a backend endpoint in order to generate a CARTO with only access to the data the user has permission for in our application, the frontend application will use that token to interact with the rest of the CARTO APIs.

The backend is responsible for generating an API Access Token without exceding the actual permissions of the users.

The data used for this guide will be the table retail_stores contains all the retails in the US, It's available at carto-demo-data.demo_tables.retail_stores.

In our demo application we will have two users:

{
  "username": "user.boston@acme.com",
  "password": "boston",
  "group": "BOSTON"
},
{
  "username": "user.ny@acme.com",
  "password": "ny",
  "group": "NEW YORK"
} 

The user in the group of BOSTON will only see the stores in the city of Boston, the user in group NEW YORK will be limited to New York.

Scaffolding your backend

mkdir backend
cd backend
npm init --yes
npm install express dotenv cors jsonwebtoken
npm i -D typescript @types/express @types/node @types/cors @types/jsonwebtoken
npx tsc --init

Now, the next step is to uncomment the following line in the file (it specifies an output folder for all emitted files):

"outDir": "./dist",

As an optional step, you would like to add to have extra help to develop by restarting your application automatically when there are changes in your code. To do that, install the following dependencies:

npm install -D concurrently nodemon

And add the following content to the file package.json:

{
    "scripts": {
        "build": "npx tsc",
        "start": "node dist/index.js",
        "dev": "concurrently \"npx tsc --watch\" \"nodemon -q dist/index.js\""
    }
}

Now, just typing npm run dev the server will run up and you can see the changes in the code immediately.

Creating a M2M OAuth Client in CARTO

For development purposes, you can set the URL for localhost in the App URL and Application Login URI. Just set the URL https://127.0.0.1:8000 in both fields.

Once the application is created, you will have to get the Client ID and the Client Secret

Coding the endpoint

Now, we have to create a couple of endpoints: a basic login endpoint to authenticate the user and an endpoint to generate the CARTO token.

For the login endpoint, the responsibilities will be:

  • Check the login and password.

  • Get the group of the user and create a JWT token.

In a real production environment, you should already have a login endpoint.

While the endpoint to get the CARTO token will do:

  • Validate the JWT in the Authentication header.

Replace the file index.ts with the following content:

import express, { Express, Request, Response } from 'express'
import dotenv from 'dotenv'
import cors from 'cors'
import jwt from 'jsonwebtoken'
import fetch from 'node-fetch'

dotenv.config()

const app: Express = express()
const port = process.env.PORT || 8000
const jwtSecret = process.env.JWT_SECRET as string

app.use(express.json())
app.use(cors())

interface LoginRequestBody {
  username: string
  password: string
}

interface LoginResponseBody {
  token: string
}

interface AccessApiTokenResponse {
  token: string
  error: string,
  description: string
}

// hard-coded users. Don't use this in production! This should come from an IdP or a database.
const users = [{
    username: 'user.boston@acme.com',
    password: 'boston',
    group: 'BOSTON'
  },
  {
    username: 'user.ny@acme.com',
    password: 'ny',
    group: 'NEW YORK'
  } 
]

// This endpoint simulates a login system. It checks the credentials and returns a JWT token
// with the user group as a claim.
app.post('/login', async (req: Request, res: Response) => {
  const { username, password } = req.body as LoginRequestBody
  const user = users.find((u) => u.username === username)

  if (!user || user.password !== password) {
    res.status(401).send({ 'error': 'Invalid credentials' })
    return
  }

  const loginToken = jwt.sign({ group: user.group }, jwtSecret, { expiresIn: '1h' })
  const loginResponse = { token: loginToken } as LoginResponseBody

  res.send(loginResponse)
})

// This endpoint returns a CARTO API Access Token for the user group. The token will be used
// to query the tables for the city of the user.
app.post('/carto-token', async (req: Request, res: Response) => {
  try {

    // Get the token from the Authorization header with Bearer prefix
    const authHeader = req.headers.authorization as string
    const loginToken = authHeader.replace('Bearer ', '')

    // Decode the token to get the group
    const tokenGroup = jwt.verify(loginToken, jwtSecret) as { group: string }
    const token = await getAPIAccessTokenForGroup(tokenGroup.group)
    const response = { token, city: tokenGroup.group } as LoginResponseBody
    res.send(response)
  } catch (error) {
    console.log(error)
    res.status(401).send({ 'error': 'Invalid token' })
  }
})

app.listen(port, () => {
  console.log(`⚡️[server]: Server is running at http://localhost:${port}`)
})

Create a .env file located in the root of the backend with the following content:

PORT=8000
# The JWT Secret to sign the JWT token
JWT_SECRET=PUT_YOUR_SECRET_HERE
# API Base URL (copy this from CARTO Workspace -> Developers)
CARTO_BASE_URL=PUT_YOUR_API_BASE_URL_HERE
# ClientID and Secret of your Machine to Machine Application
CARTO_CLIENT_ID=PUT_YOUR_CLIENT_ID_HERE
CARTO_CLIENT_SECRET=PUT_YOUR_CLIENT_ID_HERE

The most important function involved in the endpoint is the one called getAPIAccessTokenForGroup that owns the logic to interact with CARTO in order to get a valid token for the frontend side. Let's see what its implementation looks like:

async function getAPIAccessTokenForGroup(group: string): Promise<string> {
  const cartoBaseUrl = process.env.CARTO_BASE_URL
  const clientId = process.env.CARTO_CLIENT_ID
  const clientSecret = process.env.CARTO_CLIENT_SECRET

  // Step 1: Get an OAuth Access Token using the clientId and clientSecret of a Machine to Machine Application.
  const accessTokenResponse = await fetch('https://auth.carto.com/oauth/token', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/x-www-form-urlencoded'
    },
    body: `grant_type=client_credentials&client_id=${clientId}&client_secret=${clientSecret}&audience=carto-cloud-native-api`
  })

  const { access_token, error } = await accessTokenResponse.json() as { access_token: string, error: string }
  if (error) {
    console.log(error)
    throw new Error(error)
  }

  // Step 2: Generate an API Access Token for the logged user (with limited grants).
  const grants = [
    {
      'connection_name': 'carto_dw',
      'source': `SELECT * FROM \`carto-demo-data\`.demo_tables.retail_stores WHERE city = @groupcity`
    }
  ]

  // Call the tokens API using the OAuth Access Token from step 1.
  const accessApiTokenResponse = await fetch(`${cartoBaseUrl}/v3/tokens`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Authorization': `Bearer ${access_token}`
    },
    body: JSON.stringify({
      'grants': grants,
      // Put here the referers of your frontend application in production
      'referers': [],
      'allowed_apis': [
        // 'sql', // Uncomment this line to allow SQL API calls
        'maps'
      ]
    })
  })

  const { token, error: tokenError, description: tokenDescription } = await accessApiTokenResponse.json() as AccessApiTokenResponse
  if (tokenError) {
    console.log(error)
    throw new Error(tokenError)
  }

  return token
}

Tokens are limited based on the quota of your plan. In a production environment, you should implement a mechanism to create only the tokens that you need:

  • API Access Tokens: avoid creating two tokens with the same grants for the same user.

  • OAuth Access Tokens: OAuth Access Tokens are valid for 24 hours, so you should avoid creating more than one token per day per application/API instance.

That means, that once the token is created, the client using this token only will have permission to execute the defined query and get only the data declared in the grants.

Finally, once the code for the backend is ready you can run the server just by typing in your terminal:

npm run dev

SELECT * FROM carto-demo-data.demo_tables.retail_stores

WHERE city = 'BOSTON' AND storetype = @storetype

Frontend side integration

At this point, our backend is ready to generate tokens for our users. In the following code you can see an example of a frontend application that does:

  • Login.

  • Use the token to call CARTO APIs.

To run this, first, you need to clone the project:

git clone https://github.com/CartoDB/carto-for-developers-guides.git
cd carto-for-developers-guides/integrate-existing-app/frontend

Edit the .env file at set the VITE_API_BASE_URL:

# API Base URL (copy this from CARTO Workspace -> Developers)
VITE_CARTO_API_BASE_URL=https://gcp-us-east1.api.carto.com
# Custom company backend
VITE_COMPANY_API_BASE_URL=http://localhost:8000

If you have a different region, you need to modify VITE_CARTO_API_BASE_URL.

Run:

npm run dev

What's next?

git clone https://github.com/CartoDB/carto-for-developers-guides.git
cd carto-for-developers-guides/integrate-existing-app

Since this guide needs a backend and a frontend application, the first thing we have to do is create the structure to store the code for these components. Let's start with the backend side and install the needed dependencies to work with :

We are going to use on both the backend and frontend sides, so we need to install the required dependencies:

In order to use the CARTO APIs you need to authenticate your requests. For a backend-side application, the recommended approach is to do so by creating a Machine to Machine OAuth Client (). To create this OAuth Client, you need to go to -> Developers -> Credentials -> Create New -> M2M OAuth Client

Extract the group and create the token via .

The function will take one parameter indicating the group in order to create the right token. The first thing to do is to get the environment variables to interact with the CARTO API. The next step is to obtain an to deal with the rest of the APIs. To get this first token you can see in the line 7 to 13 how to use the Client ID and the Client Secret to make the request and get this token. Once, you have a valid OAuth Access Token, the last step is to create an for the specific grants. In this case, the grants include the permission to execute a specific SQL query to get all the retail for a specific city.

If your application requires dynamic queries, you can use in and API.

Call the previous endpoint to get an with the permissions limited to the user.

All the code for this guide is available on .

We recommend you to visit Visualization with deck.gl to learn more about the different visualizations you can create using deck.gl. There are many examples in our that might be useful to improve your application!

Express
Typescript
M2M OAuth Client
CARTO Workspace
CARTO API
OAuth Access Token
API Access Token
API Access Token
GitHub
gallery
authentication strategies
API Access Token
query parameters
SQL
Maps
Architecture diagram of a private application with custom auth mechanism
How to create a Machine to Machine application
Sample web application integrating a custom backend with CARTO