The scenario you describe, where a customer has a Google cloud account and you as a third party want to act on the customer's behalf, is a central feature of OAuth 2. Unfortunately, because it involves 3 different parties sharing credential stuff, it's also the most complex way to authenticate with Google Cloud. The way this works is that your app requests the user's consent, the user tells Google about that consent, and Google gives you credentials to act on that user's behalf. Because there are three parties involved, this is called 3-legged OAuth (3LO).
Here's an overview of this OAuth flow: https://developers.google.com/identity/protocols/OAuth2WebServer#overview
And here's an example of building this using the Java library: https://developers.google.com/api-client-library/java/google-api-java-client/oauth2#web_server_applications
Here's the important section of Java code from that example:
public class CalendarServletSample extends AbstractAuthorizationCodeServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException {
// do stuff
}
@Override
protected String getRedirectUri(HttpServletRequest req) throws ServletException, IOException {
GenericUrl url = new GenericUrl(req.getRequestURL().toString());
url.setRawPath("/oauth2callback");
return url.build();
}
@Override
protected AuthorizationCodeFlow initializeFlow() throws IOException {
return new GoogleAuthorizationCodeFlow.Builder(
new NetHttpTransport(), JacksonFactory.getDefaultInstance(),
"[[ENTER YOUR CLIENT ID]]", "[[ENTER YOUR CLIENT SECRET]]",
Collections.singleton(CalendarScopes.CALENDAR)).setDataStoreFactory(
DATA_STORE_FACTORY).setAccessType("offline").build();
}
@Override
protected String getUserId(HttpServletRequest req) throws ServletException, IOException {
// return user ID
}
}
public class CalendarServletCallbackSample extends AbstractAuthorizationCodeCallbackServlet {
@Override
protected void onSuccess(HttpServletRequest req, HttpServletResponse resp, Credential credential)
throws ServletException, IOException {
resp.sendRedirect("/");
}
@Override
protected void onError(
HttpServletRequest req, HttpServletResponse resp, AuthorizationCodeResponseUrl errorResponse)
throws ServletException, IOException {
// handle error
}
@Override
protected String getRedirectUri(HttpServletRequest req) throws ServletException, IOException {
GenericUrl url = new GenericUrl(req.getRequestURL().toString());
url.setRawPath("/oauth2callback");
return url.build();
}
@Override
protected AuthorizationCodeFlow initializeFlow() throws IOException {
return new GoogleAuthorizationCodeFlow.Builder(
new NetHttpTransport(), JacksonFactory.getDefaultInstance()
"[[ENTER YOUR CLIENT ID]]", "[[ENTER YOUR CLIENT SECRET]]",
Collections.singleton(CalendarScopes.CALENDAR)).setDataStoreFactory(
DATA_STORE_FACTORY).setAccessType("offline").build();
}
@Override
protected String getUserId(HttpServletRequest req) throws ServletException, IOException {
// return user ID
}
}
You should note that this code is built around the common Java "Servlet" model, and it also assumes you're using some sort of data store to remember the refresh tokens for your users. The end result of the whole OAuth dance is you getting a "refresh token", which you can periodically use to gain a temporary "session token" that can last for up to an hour. You'll need to use some sort of data store to remember all of these tokens.