# Authentication in browsers

# Use access tokens instead of API keys

We strongly recommend that you don't use API keys in web applications since the API key is easily readable by everyone with access to the application. Another restriction is that all users of your app share the same API key. All users will have the same access level, you lose tracing/auditing per user, keys are not time-limited, etc.

Instead of API keys, use access tokens. These are short-lived tokens that grant the user access to CDF. The application gets an access token by asking the user (or client credential) to sign in to a CDF project's identity provider (Google, Active Directory, etc.).

The access token expires after a time, and as a result, the user will get 401 from CDF again, and the SDK triggers a new authentication process.

# Accessing different clusters

Cognite operates multiple clusters. The default cluster api.cognitedata.com will be used unless you override it. To access projects on a different cluster, use the baseUrl (opens new window) parameter in the SDK constructor.

// Specify the cluster `bluefield`
const client = new CogniteClient({
  appId: 'sample-app',
  baseUrl: 'https://bluefield.cognitedata.com',
  project: 'demo-project',
  getToken: ...
});
1
2
3
4
5
6
7

# How to authenticate with the SDK?

Quickly summarized, the application passes a getToken callback to the SDK and uses it to get and renew tokens as needed. Note that the SDK comes with an implementation of the Cognite legacy authentication flow, but it does not come with an implementation for all IDPs. If you need to integrate your application and the SDK with, for example, Azure Active Directory, use the appropriate library from Microsoft. If you need to integrate with Auth0, use their libraries and integrate with the SDK via getToken.

# OpenID Connect (OIDC)

See this article (opens new window) for details about OIDC and Cognite.

# OIDC authentication using code authorization w pkce

This example shows how to use the Microsoft msal (opens new window) library to get a token from Azure Active directory on behalf of a user using the authorization code flow (opens new window) with pkce (opens new window):

import { Configuration, PublicClientApplication } from "@azure/msal-browser";
import { CogniteClient } from "@cognite/sdk";
const cluster = process.env.REACT_APP_CLUSTER || 'api'
const baseUrl = `https://${cluster}.cognitedata.com`;
const scopes = [
  `${baseUrl}/DATA.VIEW`,
  `${baseUrl}/IDENTITY`
];
// MSAL configuration
const configuration: Configuration = {
  auth: {
    clientId: "$AZURE_APP_ID",
    authority: "https://login.microsoftonline.com/$AZURE_TENANT_ID",
  },
};
const pca = new PublicClientApplication(configuration);
const getToken = async () => {
  const accountId = "some-id";
  const account = pca.getAccountByLocalId(accountId)!;
  const token = await pca.acquireTokenSilent({
    account,
    scopes,
  }).catch(e => {
    return pca.acquireTokenPopup({
    account,
    scopes,
    });
  });
  return token.accessToken;
};
const client = new CogniteClient({
  project: "my-project",
  appId: "demo-sample",
  getToken
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

You can find a full sample application here and here.

# OIDC authentication using client credentials

This flow gets a token on behalf of a client credential (opens new window). This is typically a non-human entity with some access to a system and is appropriate for background operations like extractors. Client credentials have a similar use case as API keys have for legacy authenticated projects.

# Example

async function quickstart() {
  const pca = new ConfidentialClientApplication({
    auth: {
      clientId,
      clientSecret,
      authority: `https://login.microsoftonline.com/${azureTenant}`,
    },
  });
  const client = new CogniteClient({
    appId: 'Cognite SDK samples',
    project,
    getToken: () =>
      pca
        .acquireTokenByClientCredential({
          scopes: ['https://api.cognitedata.com/.default'],
          skipCache: true,
        })
        .then((response) => response?.accessToken! as string),
  });
  await client.authenticate();
  const info = (await client.get('/api/v1/token/inspect')).data;
  console.log('tokenInfo', JSON.stringify(info, null, 2));
  try {
    const assets = await client.assets.list();
    console.log(assets);
  } catch (e) {
    console.log('asset error');
    console.log(e);
  } //
}
quickstart()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

Demo project

# CDF auth flow

CDF auth flow, also called legacy auth flow, is a deprecated method of getting access to CDF projects. It is the predecessor of OIDC, OpenId Connect.

The legacy flow for the user using your application:

  1. The user uses your app on this URL: https://my-app.com/some/path?someQuery=someValue
  2. The SDK redirects the user to the project's identity provider.
  3. After a successful login, the browser redirects the user to the URL: https://my-app.com/some/path?someQuery=someValue&access_token=someToken&id_token=someToken
  4. The app initializes again and calls createClientWithOAuth again
  5. The SDK sees the query parameters access_token and id_token in the URL. It parses them and removes them from the URL
  6. The SDK is authenticated (using the access token from the URL)

There are two ways to authenticate using the CDF auth flow:

# Legacy authentication with redirects

When authenticating with redirects, the browser window is redirected to the identity provider for the user to sign in. After signing in, the browser window redirects back to your application.

# Example

import { CogniteClient, REDIRECT, CogniteAuthentication } from '@cognite/sdk';
const project = 'YOUR PROJECT NAME HERE';
const legacyInstance = new CogniteAuthentication({
  project,
});
const getToken = async () => {
  await legacyInstance.handleLoginRedirect();
  let token = await legacyInstance.getCDFToken();
  if (token) {
    return token.accessToken;
  }
  token = await legacyInstance.login({ onAuthenticate: REDIRECT });
  if (token) {
    return token.accessToken;
  }
  throw new Error("error");
};
const client = new CogniteClient({
  project,
  getToken,
  ...
});
// then use the SDK:
const assets = await client.assets.retrieve([{ id: 23232789217132 }]);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

You can find a complete example application here.

The first time this is run, the user getd a 401 response from CDF in the first call to client.assets. This triggers the SDK to perform a redirect of the browser window to authenticate.

The second time client.assets is called, the SDK is authenticated and the call succeeds.

# Legacy authentication with pop-up

When authenticating with popups, the current browser window of your application remains the same, but a new window will pop-up asking the user to sign in to the identity provider. After a successful sign-in, the popup window automatically closes.

# Example

import {
  CogniteClient,
  POPUP,
  CogniteAuthentication,
  loginPopupHandler,
  isLoginPopupWindow,
} from "@cognite/sdk";
const project = "some-project";
const baseUrl = "https://greenfield.cognitedata.com";
const legacyInstance = new CogniteAuthentication({
  project,
  baseUrl
});
if (isLoginPopupWindow()) {
  loginPopupHandler();
}
const getToken = async () => {
  await legacyInstance.handleLoginRedirect();
  let token = await legacyInstance.getCDFToken();
  if (token) {
    return token.accessToken;
  }
  token = await legacyInstance.login({ onAuthenticate: POPUP });
  if (token) {
    return token.accessToken;
  }
  throw new Error("error");
};
const client = new CogniteClient({
  appId: "masl-demo",
  project,
  getToken,
});
const assets = await client.assets.retrieve([{ id: 23232789217132 }]);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

You can find an example application using popups here.

The first time this runs, the user get a 401-response from CDF in the first call to client.assets. This triggers the SDK to perform authentication of the user using a pop-up window. A new pop-up window shows the sign-in screen of the identity provider.

After a successful sign-in, the pop-up window redirects back to your app (the same URL as the main browser window) where sdk.loginPopupHandler is executed and handles the tokens in the URL and closes the window. It is important that sdk.loginPopupHandler runs when the pop-up window is redirected back to your app (otherwise the authentication process will fail).

After a successful authentication process, the SDK automatically retries the client.assets request and eventually resolves and returns the correct result.

# API keys

API keys use the same API in the SDK, getToken, but you need to set the additional flag apiKeyMode to true to handle headers appropriately.

const client = new CogniteClient({
  appId: 'api-key-app',
  project: 'demo-project',
  apiKeyMode: true,
  getToken: () => Promise.resolve('API_KEY_HERE')
});
1
2
3
4
5
6

# Manually trigger authentication

Instead of waiting for the first 401 response, you can trigger the authentication flow manually like this:


const client = new CogniteClient({ ... });
await client.authenticate(); // this also returns the token received
1
2
3

# Cache access tokens

If you already have an access token, you can use it to skip the authentication flow. If the token is invalid or timed out, the SDK triggers a standard auth-flow on the first 401-response from CDF.

const client  = new CogniteClient({
  project: 'YOUR PROJECT NAME HERE',
  getToken: () => Promise.resolve('ACCESS TOKEN FOR THE PROJECT HERE')
});
1
2
3
4
5

# More

Read more about the authentication process (opens new window).