Authenticate installed apps with user accounts

This guide explains how to authenticate by using user accounts for access tothe BigQuery API when your app is installed onto users' machines.

To ensure the app accesses only BigQuerytables that are available to the end user, authenticate by using a user credential. A usercredential can run queries against only the enduser's Google Cloud project rather than the app's project. As a result,the user is billed for queries instead of the app.

Before you begin

  1. Create a Google Cloud project that represents your installed app.
  2. Install theBigQuery client libraries.
  3. Install authentication libraries.

    Java

    If you are using Maven, include the following dependencies in your pom file.

    <dependency><groupId>com.google.oauth-client</groupId><artifactId>google-oauth-client-java6</artifactId><version>1.31.0</version></dependency><dependency><groupId>com.google.oauth-client</groupId><artifactId>google-oauth-client-jetty</artifactId><version>1.31.0</version></dependency>

    Python

    Install theoauthlib integration for Google Auth.

    pip install --upgrade google-auth-oauthlib

    Node.js

    Install theoauthlib integration for Google Auth.

    npm install google-auth-library
    npm install readline-promise

Set up your client credentials

Use the following button to select a project and create the required credentials.

Get Credentials

Manually create credentials

  1. Go to theCredentials page in the Google Cloud console.
  2. Fill out the required fields on theOAuth consent screen.
  3. On theCredentials page, click theCreate credentials button.

    ChooseOAuth client ID.

  4. SelectDesktop as the app type, and then clickCreate.
  5. Download the credentials by clicking theDownload JSON button.

    Download JSON.

    Save the credentials file toclient_secrets.json. This file must be distributed with your app.

Authenticate and call the API

  1. Use the client credentials to perform theOAuth 2.0 flow.

    Java

    importcom.google.api.client.auth.oauth2.Credential;importcom.google.api.client.extensions.java6.auth.oauth2.AuthorizationCodeInstalledApp;importcom.google.api.client.extensions.jetty.auth.oauth2.LocalServerReceiver;importcom.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeFlow;importcom.google.api.client.googleapis.auth.oauth2.GoogleClientSecrets;importcom.google.api.client.googleapis.javanet.GoogleNetHttpTransport;importcom.google.api.client.json.JsonFactory;importcom.google.api.client.json.jackson2.JacksonFactory;importcom.google.api.client.util.store.FileDataStoreFactory;importcom.google.api.gax.paging.Page;importcom.google.auth.oauth2.GoogleCredentials;importcom.google.auth.oauth2.UserCredentials;importcom.google.cloud.bigquery.BigQuery;importcom.google.cloud.bigquery.BigQueryException;importcom.google.cloud.bigquery.BigQueryOptions;importcom.google.cloud.bigquery.Dataset;importcom.google.common.collect.ImmutableList;importjava.io.File;importjava.io.IOException;importjava.io.InputStream;importjava.io.InputStreamReader;importjava.nio.file.Files;importjava.nio.file.Path;importjava.nio.file.Paths;importjava.security.GeneralSecurityException;importjava.util.List;// Sample to authenticate by using a user credentialpublicclassAuthUserFlow{privatestaticfinalFileDATA_STORE_DIR=newFile(AuthUserFlow.class.getResource("/").getPath(),"credentials");privatestaticfinalJsonFactoryJSON_FACTORY=JacksonFactory.getDefaultInstance();// i.e redirect_uri http://localhost:61984/CallbackprivatestaticfinalintLOCAL_RECEIVER_PORT=61984;publicstaticvoidrunAuthUserFlow(){// TODO(developer): Replace these variables before running the sample./**     * Download your OAuth2 configuration from the Google Developers Console API Credentials page.     * https://console.cloud.google.com/apis/credentials     */PathcredentialsPath=Paths.get("path/to/your/client_secret.json");List<String>scopes=ImmutableList.of("https://www.googleapis.com/auth/bigquery");authUserFlow(credentialsPath,scopes);}publicstaticvoidauthUserFlow(PathcredentialsPath,List<String>selectedScopes){// Reading credentials filetry(InputStreaminputStream=Files.newInputStream(credentialsPath)){// Load client_secret.json fileGoogleClientSecretsclientSecrets=GoogleClientSecrets.load(JSON_FACTORY,newInputStreamReader(inputStream));StringclientId=clientSecrets.getDetails().getClientId();StringclientSecret=clientSecrets.getDetails().getClientSecret();// Generate the url that will be used for the consent dialog.GoogleAuthorizationCodeFlowflow=newGoogleAuthorizationCodeFlow.Builder(GoogleNetHttpTransport.newTrustedTransport(),JSON_FACTORY,clientSecrets,selectedScopes).setDataStoreFactory(newFileDataStoreFactory(DATA_STORE_DIR)).setAccessType("offline").setApprovalPrompt("auto").build();// Exchange an authorization code for  refresh tokenLocalServerReceiverreceiver=newLocalServerReceiver.Builder().setPort(LOCAL_RECEIVER_PORT).build();Credentialcredential=newAuthorizationCodeInstalledApp(flow,receiver).authorize("user");// OAuth2 Credentials representing a user's identity and consentGoogleCredentialscredentials=UserCredentials.newBuilder().setClientId(clientId).setClientSecret(clientSecret).setRefreshToken(credential.getRefreshToken()).build();// Initialize client that will be used to send requests. This client only needs to be created// once, and can be reused for multiple requests.BigQuerybigquery=BigQueryOptions.newBuilder().setCredentials(credentials).build().getService();Page<Dataset>datasets=bigquery.listDatasets(BigQuery.DatasetListOption.pageSize(100));if(datasets==null){System.out.println("Dataset does not contain any models");return;}datasets.iterateAll().forEach(dataset->System.out.printf("Success! Dataset ID: %s ",dataset.getDatasetId()));}catch(BigQueryException|IOException|GeneralSecurityExceptionex){System.out.println("Project does not contain any datasets \n"+ex.toString());}}}

    Python

    fromgoogle_auth_oauthlibimportflow# A local server is used as the callback URL in the auth flow.appflow=flow.InstalledAppFlow.from_client_secrets_file("client_secrets.json",scopes=["https://www.googleapis.com/auth/bigquery"])# This launches a local server to be used as the callback URL in the desktop# app auth flow. If you are accessing the application remotely, such as over# SSH or a remote Jupyter notebook, this flow will not work. Use the# `gcloud auth application-default login --no-browser` command or workload# identity federation to get authentication tokens, instead.#appflow.run_local_server()credentials=appflow.credentials

    Node.js

    const{OAuth2Client}=require('google-auth-library');constreadline=require('readline-promise').default;functionstartRl(){constrl=readline.createInterface({input:process.stdin,output:process.stdout,});returnrl;}/** * Download your OAuth2 configuration from the Google * Developers Console API Credentials page. * https://console.cloud.google.com/apis/credentials */constkeys=require('./oauth2.keys.json');/** * Create a new OAuth2Client, and go through the OAuth2 content * workflow. Return the full client to the callback. */asyncfunctiongetRedirectUrl(){constrl=main.startRl();// Create an oAuth client to authorize the API call.  Secrets are kept in a `keys.json` file,// which should be downloaded from the Google Developers Console.constoAuth2Client=newOAuth2Client(keys.installed.client_id,keys.installed.client_secret,keys.installed.redirect_uris[0]);// Generate the url that will be used for the consent dialog.constauthorizeUrl=oAuth2Client.generateAuthUrl({access_type:'offline',scope:'https://www.googleapis.com/auth/bigquery',prompt:'consent',});console.info(`Please visit this URL to authorize this application:${authorizeUrl}`);constcode=awaitrl.questionAsync('Enter the authorization code: ');consttokens=awaitmain.exchangeCode(code);rl.close();returntokens;}// Exchange an authorization code for an access tokenasyncfunctionexchangeCode(code){constoAuth2Client=newOAuth2Client(keys.installed.client_id,keys.installed.client_secret,keys.installed.redirect_uris[0]);constr=awaitoAuth2Client.getToken(code);console.info(r.tokens);returnr.tokens;}asyncfunctionauthFlow(projectId='project_id'){/**   * TODO(developer):   * Save Project ID as environment variable PROJECT_ID="project_id"   * Uncomment the following line before running the sample.   */// projectId = process.env.PROJECT_ID;consttokens=awaitmain.getRedirectUrl();constcredentials={type:'authorized_user',client_id:keys.installed.client_id,client_secret:keys.installed.client_secret,refresh_token:tokens.refresh_token,};return{projectId,credentials,};}
  2. Use the authenticated credentials to connect to the BigQuery API.

    Java

    importcom.google.api.client.auth.oauth2.Credential;importcom.google.api.client.extensions.java6.auth.oauth2.AuthorizationCodeInstalledApp;importcom.google.api.client.extensions.jetty.auth.oauth2.LocalServerReceiver;importcom.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeFlow;importcom.google.api.client.googleapis.auth.oauth2.GoogleClientSecrets;importcom.google.api.client.googleapis.javanet.GoogleNetHttpTransport;importcom.google.api.client.json.JsonFactory;importcom.google.api.client.json.jackson2.JacksonFactory;importcom.google.api.client.util.store.FileDataStoreFactory;importcom.google.auth.oauth2.GoogleCredentials;importcom.google.auth.oauth2.UserCredentials;importcom.google.cloud.bigquery.BigQuery;importcom.google.cloud.bigquery.BigQueryException;importcom.google.cloud.bigquery.BigQueryOptions;importcom.google.cloud.bigquery.QueryJobConfiguration;importcom.google.cloud.bigquery.TableResult;importcom.google.common.collect.ImmutableList;importjava.io.File;importjava.io.IOException;importjava.io.InputStream;importjava.io.InputStreamReader;importjava.nio.file.Files;importjava.nio.file.Path;importjava.nio.file.Paths;importjava.security.GeneralSecurityException;importjava.util.List;// Sample to query by using a user credentialpublicclassAuthUserQuery{privatestaticfinalFileDATA_STORE_DIR=newFile(AuthUserQuery.class.getResource("/").getPath(),"credentials");privatestaticfinalJsonFactoryJSON_FACTORY=JacksonFactory.getDefaultInstance();// i.e redirect_uri http://localhost:61984/CallbackprivatestaticfinalintLOCAL_RECEIVER_PORT=61984;publicstaticvoidrunAuthUserQuery(){// TODO(developer): Replace these variables before running the sample./**     * Download your OAuth2 configuration from the Google Developers Console API Credentials page.     * https://console.cloud.google.com/apis/credentials     */PathcredentialsPath=Paths.get("path/to/your/client_secret.json");List<String>scopes=ImmutableList.of("https://www.googleapis.com/auth/bigquery");Stringquery="SELECT name, SUM(number) as total"+"  FROM `bigquery-public-data.usa_names.usa_1910_current`"+"  WHERE name = 'William'"+"  GROUP BY name;";authUserQuery(credentialsPath,scopes,query);}publicstaticvoidauthUserQuery(PathcredentialsPath,List<String>selectedScopes,Stringquery){// Reading credentials filetry(InputStreaminputStream=Files.newInputStream(credentialsPath)){// Load client_secret.json fileGoogleClientSecretsclientSecrets=GoogleClientSecrets.load(JSON_FACTORY,newInputStreamReader(inputStream));StringclientId=clientSecrets.getDetails().getClientId();StringclientSecret=clientSecrets.getDetails().getClientSecret();// Generate the url that will be used for the consent dialog.GoogleAuthorizationCodeFlowflow=newGoogleAuthorizationCodeFlow.Builder(GoogleNetHttpTransport.newTrustedTransport(),JSON_FACTORY,clientSecrets,selectedScopes).setDataStoreFactory(newFileDataStoreFactory(DATA_STORE_DIR)).setAccessType("offline").setApprovalPrompt("auto").build();// Exchange an authorization code for  refresh tokenLocalServerReceiverreceiver=newLocalServerReceiver.Builder().setPort(LOCAL_RECEIVER_PORT).build();Credentialcredential=newAuthorizationCodeInstalledApp(flow,receiver).authorize("user");// OAuth2 Credentials representing a user's identity and consentGoogleCredentialscredentials=UserCredentials.newBuilder().setClientId(clientId).setClientSecret(clientSecret).setRefreshToken(credential.getRefreshToken()).build();// Initialize client that will be used to send requests. This client only needs to be created// once, and can be reused for multiple requests.BigQuerybigquery=BigQueryOptions.newBuilder().setCredentials(credentials).build().getService();QueryJobConfigurationqueryConfig=QueryJobConfiguration.newBuilder(query).build();TableResultresults=bigquery.query(queryConfig);results.iterateAll().forEach(row->row.forEach(val->System.out.printf("%s,",val.toString())));System.out.println("Query performed successfully.");}catch(BigQueryException|IOException|GeneralSecurityException|InterruptedExceptionex){System.out.println("Query not performed \n"+ex.toString());}}}

    Python

    fromgoogle.cloudimportbigquery# TODO: Uncomment the line below to set the `project` variable.# project = 'user-project-id'## The `project` variable defines the project to be billed for query# processing. The user must have the bigquery.jobs.create permission on# this project to run a query. See:# https://cloud.google.com/bigquery/docs/access-control#permissionsclient=bigquery.Client(project=project,credentials=credentials)query_string="""SELECT name, SUM(number) as totalFROM `bigquery-public-data.usa_names.usa_1910_current`WHERE name = 'William'GROUP BY name;"""results=client.query_and_wait(query_string)# Print the results.forrowinresults:# Wait for the job to complete.print("{}:{}".format(row["name"],row["total"]))

    Node.js

    asyncfunctionquery(){const{BigQuery}=require('@google-cloud/bigquery');constcredentials=awaitmain.authFlow();constbigquery=newBigQuery(credentials);// Queries the U.S. given names dataset for the state of Texas.constquery=`SELECT name, SUM(number) as total  FROM \`bigquery-public-data.usa_names.usa_1910_current\`  WHERE name = 'William'  GROUP BY name;`;// For all options, see https://cloud.google.com/bigquery/docs/reference/rest/v2/jobs/queryconstoptions={query:query,};// Run the query as a jobconst[job]=awaitbigquery.createQueryJob(options);console.log(`Job${job.id} started.`);// Wait for the query to finishconst[rows]=awaitjob.getQueryResults();// Print the resultsconsole.log('Rows:');rows.forEach(row=>console.log(row));returnrows;}constmain={query,authFlow,exchangeCode,getRedirectUrl,startRl,};module.exports={main,};if(module===require.main){query().catch(console.error);}

When you run the sample code, it launches a browser that requests access tothe project that is associated with the client secrets. You can use the resulting credentialsto access the user's BigQuery resources because the samplerequested theBigQueryscope.

What's next

  1. Learn aboutother ways to authenticate your app to access the BigQuery API.
  2. Learn aboutauthentication with end user credentials for all Cloud APIs.

Except as otherwise noted, the content of this page is licensed under theCreative Commons Attribution 4.0 License, and code samples are licensed under theApache 2.0 License. For details, see theGoogle Developers Site Policies. Java is a registered trademark of Oracle and/or its affiliates.

Last updated 2025-12-15 UTC.