Authenticate as an end user a Spring Boot app for access to the BigQuery API

Paul Bares
4 min readSep 20, 2022

--

This guide explains how web server applications written with Spring Boot can use Google OAuth 2.0 endpoints to implement OAuth 2.0 authorization to access Google APIs and use Spring authentication for access to the BigQuery API.

This is to ensure the app accesses only BigQuery tables and table rows that are available to the end user.

Configure APIs & Services

First, start to by configuring the OAuth consent screen. Follow those steps: https://developers.google.com/workspace/guides/configure-oauth-consent

Click on Add or Remove scopes and select bigquery.readonly in order to be able to read data on behalf of the authenticated user.

Once it is done, go to Credentials and click on CREATE CREDENTIALS, choose OAuth Client ID in the dropdown list

Application type: Web application (we are configuring it for a Spring Boot app)

In Authorized redirect URIs field, set http://localhost:8080/login/oauth2/code/google. login/oauth2/code/google is the default redirect URI of Google. Add the production URL when needed. Click on Save. A popup will show you client id and secret. Store them your are going to need them to configure your Spring Boot app.

At this point, if you try to edit the OAuth consent screen to add or remove roles, you might see a message stating

This scope is unavailable because this project has non-https URLs in OAuth clients

To circumvent this issue, remove all non-https URLs configured in your OAuth clients, edit the consent screen and add back your non-https URLs.

Configure Spring Boot app

You need to add this dependency to your project

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>

Create your security config

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest().authenticated()
.and()
.oauth2Login();
}
}

In src/main/resources, create or edit application.properties file and add

spring.security.oauth2.client.registration.google.client-id=your-client-id
spring.security.oauth2.client.registration.google.client-secret=your-client-secret
spring.security.oauth2.client.registration.google.scope=openid,https://www.googleapis.com/auth/bigquery

Do not forget to add BigQuery API scope to the config by using its key

https://www.googleapis.com/auth/bigquery

If you don’t, you will have this issue later on when trying to fetch the list of the tables.

com.google.api.client.googleapis.json.GoogleJsonResponseException: 403 Forbidden
GET https://www.googleapis.com/bigquery/v2/projects/********/datasets/********/tables?prettyPrint=false
{
"code" : 403,
"details" : [ {
"@type" : "type.googleapis.com/google.rpc.ErrorInfo",
"reason" : "ACCESS_TOKEN_SCOPE_INSUFFICIENT"
} ],
"errors" : [ {
"domain" : "global",
"message" : "Insufficient Permission",
"reason" : "insufficientPermissions"
} ],
"message" : "Request had insufficient authentication scopes.",
"status" : "PERMISSION_DENIED"
}

List of admissible keys are available here https://developers.google.com/identity/protocols/oauth2/scopes

At this point, if you try to access to any URL in your web browser, you will be redirected to the Google Authentication form:

Next, you will be shown the consent screen

Use BigQuery Java client

Now let’s try it out to fetch the list of the tables the current authenticated user is allowed to see. Start by adding the java lib

<dependency>
<groupId>com.google.cloud</groupId>
<artifactId>google-cloud-bigquery</artifactId>
</dependency>

Let’s see how to use it in a controller. Here’s the starting point

@RestController
class HelloWorldController {

@Autowired
OAuth2AuthorizedClientRepository authorizedClientRepository;

@Autowired
Environment environment;

@GetMapping("/")
public String hello(Principal principal) {
System.out.println("Authenticated user: " + principal);
return "hello";
}
}

Inject Principal object to your endpoint, we will use it to extract what we need.

To fetch the list of the tables from BigQuery, the code is simple

Credentials credentials = ???
String projectId = "your-google-project-id";
String datasetName = "your-bigquery-dataset-name";
BigQuery bigquery = BigQueryOptions.newBuilder()
.setCredentials(credentials)
.setProjectId(projectId)
.build()
.getService();

Set<String> tableNames = new HashSet<>();
bigquery.listTables(datasetName)
.getValues().iterator().forEachRemaining(t -> tableNames.add(t.getTableId().getTable()));
System.out.println("List of tables: " + tableNames);

The only thing that is missing is the Google credentials to be able to execute an authenticated request to BigQuery. To do so, we can use the information stored in Principal object to convert it to com.google.auth.oauth2.Credentials type.

That’s it!

Full code

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

--

--

Paul Bares
Paul Bares

Written by Paul Bares

I'm an enthusiast in computer hardware and programming. I specialize in high performance and parallel computing. Co-Creator of SquashQL Github: squashql

No responses yet

Write a response