Looker uses OAuth to let OAuth client applications authenticate into the Looker API without exposing client IDs and client secrets to the browser that is running the OAuth client application.
Web applications using OAuth must meet the following requirements:
- Authentication using OAuth is available only with the Looker API 4.0.
- OAuth client applications must first be registered with Looker using the API before users of the application can authenticate into Looker.
- Client applications must use HTTPS for all requests to the Looker API. Client applications that want to use the
SubtleCrypto
APIs provided by the browser must be HTTPS hosted.
Looker API CORS support
The Looker API supports being called in browser and across origins using the Cross-Origin Resource Sharing (CORS) protocol. Looker CORS support has the following requirements:
- Only origins listed in the embedded domain allowlist can call the API using CORS.
Only access tokens obtained from OAuth, or from calling the
/login
API endpoint, can be used to make calls to the Looker API using CORS.The
/login
API endpoint cannot be called using CORS requests. Client applications wanting to call the Looker API using CORS requests must either use the OAuth login process described in Performing User Login Using OAuth, or retrieve a token from your application server or from non-CORS API calls.
OAuth authentication overview
An overview of the OAuth authentication process is as follows:
- Register the OAuth client application with the Looker API.
- Add the origin of your OAuth client application to your embedded domain allowlist for the code exchange API call and any subsequent CORS API calls.
- Redirect the browser URL to the
/auth
endpoint on the Looker UI hostname (not the Looker API hostname) when the OAuth client application attempts to authenticate a user. For example,https://instance_name.looker.com
. - If the user is successfully authenticated and logged in to Looker, Looker returns an OAuth redirect to the OAuth client application immediately. If the user is not already logged in to Looker on the device and browser, the Looker login screen is displayed and the user is prompted to log in to their Looker user account using their regular authentication protocol.
- Using the authorization code returned in the OAuth redirect, your OAuth client application should next make a call to the
/token
endpoint on the Looker API hostname, for example,https://instance_name.looker.com:19999
. The API hostname might be the same as or different from the Looker UI hostname. The/token
endpoint exists only on the Looker API host, and the/auth
endpoint exists only on the Looker UI host. - If the authorization code passed to the
/token
endpoint is valid, Looker returns an APIaccess_token
that is enabled for CORS API requests from the OAuth client application's domain.
Registering an OAuth client application
Every OAuth client application that attempts to authenticate into the Looker API using OAuth must first be registered with the Looker instance before Looker will authorize access. To register an OAuth client application:
- Open the API Explorer on your Looker instance.
- Using the version drop-down menu, choose the 4.0 - stable version of the API.
Under the Auth method, find the
register_oauth_client_app()
API endpoint. You can also search for "oauth app" in the Search field. You can useregister_oauth_client_app()
to register your OAuth client application with Looker. Click the Run It button, and enter the parameters in the API Explorer and click Run It again to register the OAuth client application, or use theregister_oauth_client_app()
API endpoint programmatically. The requiredregister_oauth_client_app()
parameters are:client_guid
: A globally unique ID for the applicationredirect_uri
: The URI where the application will receive an OAuth redirect that includes an authorization codedisplay_name
: The name of the application that is displayed to users of the applicationdescription
: A description of the application that is displayed to users on a disclosure and confirmation page when a user first logs in from the application
The values in the
client_guid
andredirect_uri
parameters must match the values the OAuth client application will provide exactly, or authentication will be denied.
Performing user login using OAuth
Navigate the user to the
/auth
endpoint on the UI host. For example:async function oauth_login() { const code_verifier = secure_random(32) const code_challenge = await sha256_hash(code_verifier) const params = { response_type: 'code', client_id: '123456', redirect_uri: 'https://mywebapp.com:3000/authenticated', scope: 'cors_api', state: '1235813', code_challenge_method: 'S256', code_challenge: code_challenge, } const url = `${base_url}?${new URLSearchParams(params).toString()}` // Replace base_url with your full Looker instance's UI host URL, plus the `/auth` endpoint. log(url) // Stash the code verifier we created in sessionStorage, which // will survive page loads caused by login redirects // The code verifier value is needed after the login redirect // to redeem the auth_code received for an access_token // sessionStorage.setItem('code_verifier', code_verifier) document.location = url } function array_to_hex(array) { return Array.from(array).map(b => b.toString(16).padStart(2,'0')).join('') } function secure_random(byte_count) { const array = new Uint8Array(byte_count); crypto.getRandomValues(array); return array_to_hex(array) } async function sha256_hash(message) { const msgUint8 = new TextEncoder().encode(message) const hashBuffer = await crypto.subtle.digest('SHA-256', msgUint8) return base64.urlEncode(hashBuffer)) // Refers to the implementation of base64.encode stored at https://gist.github.com/jhurliman/1250118 }
Looker will attempt to authenticate the user using the authentication system for which the Looker instance is configured.
- If the user is already logged in to Looker in the current browser (meaning there is a live login cookie state), the user won't be prompted to enter their login credentials.
- If this is the first time this user has logged in using this OAuth client application, Looker will show a disclosure and confirmation page for the user to acknowledge and accept. The text from the
description
parameter used when the application was registered will be displayed. The description should indicate what the application intends to do with the user's Looker account. When the user clicks accept, the page will redirect to the applicationredirect_uri
. - If the user is already logged in to Looker in the current browser and has already acknowledged the disclosure page, then the OAuth login is instantaneous with no visual interruption.
The Looker API will return an OAuth redirect to the OAuth client application. Save the authorization code listed in the URI parameter. The following is an example OAuth redirect URI:
https://mywebapp.com:3000/authenticated?&code=asdfasdfassdf&state=...
The authorization code is shown after
&code=
in the URI. In this example, the authorization code isasdfasdfassdf
.Make a web request to the
/token
endpoint in the Looker API, passing the authorization code and your application information. For example:async function redeem_auth_code(response_str) { const params = new URLSearchParams(response_str) const auth_code = params.get('code') if (!auth_code) { log('ERROR: No authorization code in response') return } log(`auth code received: ${auth_code}`) log(`state: ${params.get('state')}`) const code_verifier = sessionStorage.getItem('code_verifier') if (!code_verifier) { log('ERROR: Missing code_verifier in session storage') return } sessionStorage.removeItem('code_verifier') const response = await fetch('https://mycompany.looker.com:19999/api/token', { // This is the URL of your Looker instance's API web service method: 'POST', mode: 'cors', // This line is required so that the browser will attempt a CORS request. body: stringify({ grant_type: 'authorization_code', client_id: '123456', redirect_uri: 'https://mywebapp.com:3000/authenticated', code: auth_code, code_verifier: code_verifier, }), headers: { 'x-looker-appid': 'Web App Auth & CORS API Demo', // This header is optional. 'Content-Type': 'application/json;charset=UTF-8' // This header is required. }, }).catch((error) => { log(`Error: ${error.message}`) }) const info = await response.json() log(`/api/token response: ${stringify(info)}`) // Store the access_token and other info, // which in this example is done in sessionStorage const expires_at = new Date(Date.now() + (info.expires_in * 1000)) info.expires_at = expires_at log(`Access token expires at ${expires_at.toLocaleTimeString()} local time.`) sessionStorage.setItem('access_info', stringify(info)) access_info = info }
A successful response will provide the OAuth client application with an API
access_token
. The response will also contain arefresh_token
, which you can use later to get a newaccess_token
without user interaction. Arefresh_token
has a one-month lifetime. Store therefresh_token
securely.All tokens in this system can be revoked by the Looker admin at any time.