Authenticate installed apps with user accounts

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

To ensure the app accesses only BigQuery tables that are available to the end user, authenticate by using a user credential. A user credential can run queries against only the end user'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 the BigQuery 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 the oauthlib integration for Google Auth.

    pip install --upgrade google-auth-oauthlib

    Node.js

    Install the oauthlib 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 the Credentials page in the Google Cloud console.
  2. Fill out the required fields on the OAuth consent screen.
  3. On the Credentials page, click the Create credentials button.

    Choose OAuth client ID.

  4. Select Desktop as the app type, and then click Create.
  5. Download the credentials by clicking the Download JSON button.

    Download JSON.

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

Authenticate and call the API

  1. Use the client credentials to perform the OAuth 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 credential
    publicclass AuthUserFlow{
    privatestaticfinalFileDATA_STORE_DIR=
    newFile(AuthUserFlow.class.getResource("/").getPath(),"credentials");
    privatestaticfinalJsonFactory JSON_FACTORY=JacksonFactory .getDefaultInstance();
    // i.e redirect_uri http://localhost:61984/Callback
    privatestaticfinalintLOCAL_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 file
    try(InputStreaminputStream=Files.newInputStream(credentialsPath)){
    // Load client_secret.json file
    GoogleClientSecrets clientSecrets=
    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.
    GoogleAuthorizationCodeFlow flow=
    newGoogleAuthorizationCodeFlow .Builder(
    GoogleNetHttpTransport .newTrustedTransport (),
    JSON_FACTORY,
    clientSecrets,
    selectedScopes)
    .setDataStoreFactory(newFileDataStoreFactory (DATA_STORE_DIR))
    .setAccessType("offline")
    .setApprovalPrompt("auto")
    .build();
    // Exchange an authorization code for refresh token
    LocalServerReceiver receiver=
    newLocalServerReceiver .Builder().setPort (LOCAL_RECEIVER_PORT).build();
    Credential credential=newAuthorizationCodeInstalledApp (flow,receiver).authorize ("user");
    // OAuth2 Credentials representing a user's identity and consent
    GoogleCredentials credentials=
    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.
    BigQuery bigquery=
    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_oauthlibimport flow
    # 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 token
    asyncfunctionexchangeCode(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 credential
    publicclass AuthUserQuery{
    privatestaticfinalFileDATA_STORE_DIR=
    newFile(AuthUserQuery.class.getResource("/").getPath(),"credentials");
    privatestaticfinalJsonFactory JSON_FACTORY=JacksonFactory .getDefaultInstance();
    // i.e redirect_uri http://localhost:61984/Callback
    privatestaticfinalintLOCAL_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 file
    try(InputStreaminputStream=Files.newInputStream(credentialsPath)){
    // Load client_secret.json file
    GoogleClientSecrets clientSecrets=
    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.
    GoogleAuthorizationCodeFlow flow=
    newGoogleAuthorizationCodeFlow .Builder(
    GoogleNetHttpTransport .newTrustedTransport (),
    JSON_FACTORY,
    clientSecrets,
    selectedScopes)
    .setDataStoreFactory(newFileDataStoreFactory (DATA_STORE_DIR))
    .setAccessType("offline")
    .setApprovalPrompt("auto")
    .build();
    // Exchange an authorization code for refresh token
    LocalServerReceiver receiver=
    newLocalServerReceiver .Builder().setPort (LOCAL_RECEIVER_PORT).build();
    Credential credential=newAuthorizationCodeInstalledApp (flow,receiver).authorize ("user");
    // OAuth2 Credentials representing a user's identity and consent
    GoogleCredentials credentials=
    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.
    BigQuery bigquery=
    BigQueryOptions .newBuilder().setCredentials(credentials).build().getService();
    QueryJobConfiguration queryConfig=QueryJobConfiguration .newBuilder(query).build();
    TableResult results=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.cloudimport bigquery
    # 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#permissions
    client = bigquery .Client (project=project, credentials=credentials)
    query_string = """SELECT name, SUM(number) as total
    FROM `bigquery-public-data.usa_names.usa_1910_current`
    WHERE name = 'William'
    GROUP BY name;
    """
    results = client.query_and_wait (query_string)
    # Print the results.
    for row in results: # 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/query
    constoptions={
    query:query,
    };
    // Run the query as a job
    const[job]=awaitbigquery.createQueryJob(options);
    console.log(`Job ${job .id} started.`);
    // Wait for the query to finish
    const[rows]=awaitjob .getQueryResults ();
    // Print the results
    console.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 to the project that is associated with the client secrets. You can use the resulting credentials to access the user's BigQuery resources because the sample requested the BigQuery scope.

What's next

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

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

Last updated 2025年10月15日 UTC.