# Build a private application

Here you will learn how to create an application that requires a login to access. This application will be only accessible to users inside your CARTO organization (regardless of their role), so you will need a CARTO user to access it.

{% hint style="info" %}
If you're building an application for an Enterprise organization that requires an integration with your own login system, you'll need to first connect and enable the [Single Sign-On (SSO)](https://docs.carto.com/carto-user-manual/settings/sso) feature in CARTO. We'll cover that in the next guide: [Build a private application using SSO](https://docs.carto.com/carto-for-developers/guides/build-a-private-application-using-sso).
{% endhint %}

The CARTO login uses the popular [OAuth 2.0](https://auth0.com/docs/authenticate/protocols/oauth) Authorization Framework protocol, so in this guide you will find an easy process to implement it, including login and logout methods.

After completing this guide you will be familiar with the following concepts:

* Scaffolding your application.
* Creating a Single Page Application OAuth Client (SPA OAuth Client).
* Managing the user login using Auth0 SDK.
* Visualizing a dataset.
* Executing a query against CARTO APIs.

<figure><img src="https://3029946802-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FybPdpmLltPkzGFvz7m8A%2Fuploads%2Fm1JD1ORzkqlU2TfE6uBl%2FPrivate%20App%20Diagram.png?alt=media&#x26;token=981d76ee-ba37-4ec2-8a28-0ccadf4cc64d" alt=""><figcaption><p>Architecture diagram of a private application with Login</p></figcaption></figure>

{% hint style="info" %}
During this guide, we're using the [CARTO Data Warehouse](https://docs.carto.com/carto-user-manual/connections/carto-data-warehouse). The process explained here is also compatible with other Warehouses like BigQuery, Snowflake, Redshift, Databricks, Oracle, or Postgres. Instead of using <mark style="color:orange;">`connection=carto_dw`</mark>, you need to use <mark style="color:orange;">connection=\<your\_connection></mark>.
{% endhint %}

## Scaffolding your application

As explained [here](#scaffolding-your-application), we recommend [Vite](https://vitejs.dev/) to manage the tooling of your app.

To make this guide faster, we're going to start using the basic CARTO template in Vite that already includes a Basemap and deck.gl.

```sh
git clone https://github.com/CartoDB/carto-for-developers-guides.git
cp -r carto-for-developers-guides/template private-app
cd private-app
npm install
npm run dev
```

After that, you should have a project up and running at <https://127.0.0.1:5173/>

## Create a SPA OAuth Client

As explained in [Key Concepts section](https://docs.carto.com/key-concepts/authentication-methods/applications#how-to-create-a-single-page-application) we need to create a SPA OAuth Client to obtain a client\_id + client\_secret that we will use to then obtain an OAuth token after the user successfully authenticates (with user and password or other methods)

Go to [Workspace](https://app.carto.com) -> Developers -> Credentials -> Create New -> SPA OAuth Client. And complete the form as follows:

<figure><img src="https://3029946802-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FybPdpmLltPkzGFvz7m8A%2Fuploads%2Fgit-blob-b30c97bbe66632efc1221b2283649cdd1cbad95e%2Fimage.png?alt=media" alt=""><figcaption></figcaption></figure>

Then, go to the <mark style="color:orange;">.env</mark> file, and uncomment VITE\_CLIENT\_ID with the value of the app that was just created.

## Managing the user login using Auth0 SDK

CARTO platform uses [Auth0](https://auth0.com) under the hood to manage the authentication and authorization. When you created a SPA application in the previous step, CARTO created a SPA application in Auth0.

Auth0 provides [SDKs](https://auth0.com/docs/libraries#spa) to manage the OAuth 2.0 workflow for Angular, Vue, React, and Vanilla Javascript. In this guide, we're going to use the Vanilla Javascript SDKs to manage the login with CARTO.

We're going to implement here two things:

* Authenticate a user following the standard OAuth 2.0 workflow.
* Use the authenticated user to obtain an [OAuth Access Token](https://docs.carto.com/carto-for-developers/key-concepts/authentication-methods/oauth-access-tokens) to call [CARTO APIs](https://docs.carto.com/carto-for-developers/key-concepts/apis).

1. Install the Auth0 SDK:

```typescript
npm install @auth0/auth0-spa-js
```

2. Create a file <mark style="color:orange;">src/auth.ts</mark>:

```typescript
import { Auth0Client, createAuth0Client } from '@auth0/auth0-spa-js';

let auth0Client: Auth0Client

export async function initAuth() {
  let accessToken: string | undefined;

  const clientId = import.meta.env.VITE_CLIENT_ID;
  auth0Client = await createAuth0Client({
    domain: 'auth.carto.com',
    clientId,
    authorizationParams: {
      redirect_uri: window.location.origin,
      audience: 'carto-cloud-native-api'
    }
  })

  if (location.search.includes('state=') && 
      (location.search.includes('code=') || 
      location.search.includes('error='))) {
    await auth0Client.handleRedirectCallback();
    window.history.replaceState({}, document.title, '/');
  }

  const isAuthenticated = await auth0Client.isAuthenticated();
  const appEl = document.getElementById('app');

  if (isAuthenticated) {
    appEl?.classList.add('isAuthenticated');
    
    const userProfile = await auth0Client.getUser();
    accessToken = await auth0Client.getTokenSilently();

    if (userProfile) {
      const profileEl = document.getElementById('profile')!;
      profileEl.innerHTML = `
            <p>${userProfile.name}</p>
            <img width="50px" height="50px" src='${userProfile.picture}' />
          `;
    }
    
  } else {
    appEl?.classList.remove('isAuthenticated');
  }
  
  // Logout
  const logoutButton = document.getElementById('logout');
  logoutButton?.addEventListener('click', (e) => {
    e.preventDefault();
    auth0Client.logout();
  });

  // Login
  const loginButton = document.getElementById('login');
  loginButton?.addEventListener('click', (e) => {
    e.preventDefault();
    auth0Client.loginWithRedirect();
  });
  
  return accessToken
}
```

3. Replace <mark style="color:orange;">src/main.ts</mark> with:

```typescript
import './style.css'
import { initAuth } from './auth'
import { createMap } from './map'

document.querySelector<HTMLDivElement>('#app')!.innerHTML = `
  <button id="login">Login</button>
  <div id="login-content">
    <header>
      <button id="logout">Logout</button>
      <div id="profile"></div>
    </header>
    <div id="map"></div>
    <canvas id="deck-canvas"></canvas>
  </div>
`

initAuth().then((accessToken) => {
  if (accessToken) {
    createMap()
  }
})
```

4. Add this at the end of <mark style="color:orange;">src/style.css:</mark>

```css
header {
  z-index: 1;
  position: absolute;
  padding: 10px;
}

#login-content {
  display: none;
}

.isAuthenticated #login-content {
  display: block;
}
.isAuthenticated #login {
  display: none;
}
```

Your application is now ready to authenticate users by sending them to the CARTO login, which will require the user to enter their own credentials, before successfully returning to the application in a classic OAuth 2.0 workflow that returns an OAuth Access Token.

## Visualizing a dataset

Once the user is logged in an OAuth Access Token will be available, and we just need to tell deck.gl to use this token.

Let's modify <mark style="color:orange;">src/main.ts:</mark>

```typescript
initAuth().then((accessToken) => {
  if (accessToken) {
    const apiBaseUrl = import.meta.env.VITE_API_BASE_URL;
    createMap({apiBaseUrl, accessToken});
  }
})
```

And prepare <mark style="color:orange;">src/map.ts</mark> to receive the new parameters, including imports:

```typescript
import { BASEMAP, vectorTableSource, VectorTileLayer } from '@deck.gl/carto';

interface createMapProps {
  apiBaseUrl: string,
  accessToken: string
}
export function createMap({apiBaseUrl, accessToken}:createMapProps) {
// ...
```

Then add the following source and layer to the Deck instance at <mark style="color:orange;">src/map.ts:</mark>

```typescript
const connectionName = 'carto_dw';
const cartoConfig = {apiBaseUrl, accessToken, connectionName};

const demoTableSource = vectorTableSource({
  ...cartoConfig,
  tableName: 'carto-demo-data.demo_tables.populated_places'
});

const deck = new Deck({
  canvas: 'deck-canvas',
  initialViewState: INITIAL_VIEW_STATE,
  controller: true,
  layers: [
    new VectorTileLayer({
      id: 'places',
      data: demoTableSource,
      pointRadiusMinPixels: 3,
      getFillColor: [200, 0, 80],
    })
  ]
})
```

{% hint style="info" %}
Remember that OAuth Access Tokens impersonate the user, so it will inherit all the permissions of the user.
{% endhint %}

## Executing a query against CARTO APIs

At this point, we're all clear to execute a query against the [CARTO SQL API](https://docs.carto.com/key-concepts/apis#sql) using the OAuth Access Token we've previously obtained.

Create a file <mark style="color:orange;">src/api.ts</mark>:

```typescript
interface ExecuteQueryProps {
  apiBaseUrl: string
  connection: string
  query: string
  accessToken: string
}
async function executeQuery ({apiBaseUrl, connection, query, accessToken}: ExecuteQueryProps) {
  const url = `${apiBaseUrl}/v3/sql/${connection}/query?q=${encodeURI(query)}`
  const options = {
    method: 'GET',
    headers: {
      'Authorization': `Bearer ${accessToken}`
    }
  };
  const response = await fetch(url, options);
  return await response.json();
}

interface GetAirportsProps {
  apiBaseUrl: string,
  accessToken: string
}
export function getAirports ({apiBaseUrl, accessToken}: GetAirportsProps) {
  const query = `select * from carto-demo-data.demo_tables.world_airports`
  const connection = 'carto_dw'
  return executeQuery({apiBaseUrl, connection, query, accessToken})
}

```

Modify <mark style="color:orange;">src/main.ts</mark> to call the `getAirports` function:

```typescript
initAuth().then((accessToken) => {
  if (accessToken) {
    const apiBaseUrl = import.meta.env.VITE_API_BASE_URL;
    setDefaultCredentials({ apiBaseUrl, accessToken})
    createMap()
    getAirports({apiBaseUrl, accessToken}).then((airports) => {
      console.log(airports)
    })
  }
})
```

**Congratulations!** You now have successfully built a private application that will require the user to log in. And after a successful login, you're able to show the user a map layer, and you're able to query an airports dataset right from your application.

## What's next?

The full code of this guide is available on [GitHub](https://github.com/CartoDB/carto-for-developers-guides/tree/master/guides/private-app).

```bash
git clone https://github.com/CartoDB/carto-for-developers-guides.git
cd carto-for-developers-guides/private-app
```

We recommend you to visit [https://github.com/CartoDB/gitbook-documentation/blob/master/carto-for-developers/key-concepts/carto-for-deck.gl](https://github.com/CartoDB/gitbook-documentation/blob/master/carto-for-developers/key-concepts/carto-for-deck.gl "mention") to learn more about the visualizations you can create in deck.gl. There are many examples in our [gallery](https://docs.carto.com/carto-for-developers/examples) that might be useful to improve your application!


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.carto.com/carto-for-developers/guides/build-a-private-application.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
