Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I get the User ID Token from a Credential object?

I have been following this tutorial to include Google Sign-in support to my Desktop app. The library I'm using is this one.

Everything works and this is the implementation of the authorize() method:

public Credential authorize() throws IOException {
    // Load client secrets.
    InputStream in = GoogleLogin.class.getResourceAsStream("/google/client_secret.json");
    GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(JSON_FACTORY, new InputStreamReader(in));

    // Build flow and trigger user authorization request.
    GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(
            HTTP_TRANSPORT, JSON_FACTORY, clientSecrets, SCOPES)
            .setDataStoreFactory(DATA_STORE_FACTORY)
            .setAccessType("offline")
            .build();

    Credential credential = new AuthorizationCodeInstalledApp(flow, new LocalServerReceiver()).authorize("user");

    System.out.println("Credentials saved to " + DATA_STORE_DIR.getAbsolutePath());
    return credential;
}

However, from a Credential object, I can only retrieve the access token by calling Credential.getAccessToken(), but what I need is the id token. How can I retrieve the id_token from the user after it's been authenticated?

like image 910
Morgan Avatar asked Mar 19 '18 02:03

Morgan


People also ask

How do I find my ID token?

To get an ID token, you need to request them when authenticating users. Auth0 makes it easy for your app to authenticate users using: Quickstarts: The easiest way to implement authentication, which can show you how to use Universal Login, the Lock widget, and Auth0's language and framework-specific SDKs.

How do I find my token username and password?

Obtaining an Access Token by Using the User Credentials Without a Client Assertion. Using the resource owner password credentials workflow, the OAuth client can obtain an access token by providing the user's credentials (that is the user name and password).

What is user ID token?

The ID token is a JSON web token (JWT) that contains claims about the identity of the authenticated user, such as name , email , and phone_number . You can use this identity information inside your application. The ID token can also be used to authenticate users to your resource servers or server applications.

How do I get an access token from an authorization server?

After you add the authorization profile, you need to get access token from the server. In this tutorial, we get it by using the Authorization Code grant method: Click Get Token. In the subsequent dialog, enter Client Identification and Secret, Authorization URI, Access Token URI and Redirect URI.


Video Answer


1 Answers

I literally figured it out after starting the bounty! It's possible to get the Id Token by inheriting from AuthorizedCodeInstalledApp and providing your own implementation of authorize()

Here's what I did...

public class GoogleAuthCodeInstalledApp extends AuthorizationCodeInstalledApp {

    public GoogleAuthCodeInstalledApp(AuthorizationCodeFlow flow, VerificationCodeReceiver receiver) {
        super(flow, receiver);
    }

    @Override
    public Credential authorize(String userId) throws IOException {
        try {
            Credential credential = getFlow().loadCredential(userId);
            if (credential != null
                    && (credential.getRefreshToken() != null
                    || credential.getExpiresInSeconds() == null
                    || credential.getExpiresInSeconds() > 60)) {
                return credential;
            }
            // open in browser
            String redirectUri = getReceiver().getRedirectUri();
            AuthorizationCodeRequestUrl authorizationUrl
                    = getFlow().newAuthorizationUrl().setRedirectUri(redirectUri);
            onAuthorization(authorizationUrl);
            // receive authorization code and exchange it for an access token
            String code = getReceiver().waitForCode();
            GoogleTokenResponse response = (GoogleTokenResponse) getFlow().newTokenRequest(code).setRedirectUri(redirectUri).execute();
            System.out.println(response.getIdToken()); //YES, THIS IS THE ID TOKEN!!!
            // store credential and return it
            return getFlow().createAndStoreCredential(response, userId);
        } finally {
            getReceiver().stop();
        }
    }

}

After you do that, instead of

Credential credential = new AuthorizationCodeInstalledApp(flow, new LocalServerReceiver()).authorize("user");

Use:

Credential credential = new GoogleAuthCodeInstalledApp(flow, new LocalServerReceiver()).authorize("user");

UPDATE 2018-05-29 - I have found a better, more reliable solution

This solution I found works by adding a CredentialCreatedListener and a CredentialRefreshListener inside our GoogleAuthorizationCodeFlow.Builder.

Here's the sample code:

public Credential authorize() throws IOException {
    InputStream in = GoogleLogin.class.getResourceAsStream("/google/client_secret.json");
    GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(JSON_FACTORY, new InputStreamReader(in));
    // Build flow and trigger user authorization request.
    flow = new GoogleAuthorizationCodeFlow.Builder(
            HTTP_TRANSPORT, JSON_FACTORY, clientSecrets, SCOPES)
            .setDataStoreFactory(DATA_STORE_FACTORY)
            .setAccessType("offline")
            .setCredentialCreatedListener(new AuthorizationCodeFlow.CredentialCreatedListener() {
                @Override
                public void onCredentialCreated(Credential credential, TokenResponse tokenResponse) throws IOException {
                    DATA_STORE_FACTORY.getDataStore("user").set("id_token", tokenResponse.get("id_token").toString());
                }
            })
            .addRefreshListener(new CredentialRefreshListener() {
                @Override
                public void onTokenResponse(Credential credential, TokenResponse tokenResponse) throws IOException {
                    DATA_STORE_FACTORY.getDataStore("user").set("id_token", tokenResponse.get("id_token").toString());
                }

                @Override
                public void onTokenErrorResponse(Credential credential, TokenErrorResponse tokenErrorResponse) throws IOException {
                    //handle token error response
                }
            })
            .build();

    Credential credential = new AuthorizationCodeInstalledApp(flow, serverReceiver).authorize("user");
    System.out.println("Credentials saved to " + DATA_STORE_DIR.getAbsolutePath());
    return credential;
}

The code is pretty much self-explanatory. Whenever a new Credential is created or refreshed by calling credential.refreshToken(), the listeners will be notified and the id_token will be taken from the TokenResponse (which is actually a GoogleTokenResponse object that contains an id_token field), and we'll use the default DataStoreFactory to save the id_token. The id_token will now be persisted locally, and will be automatically updated by the listeners whenever credential.refreshToken() is called.

like image 145
Morgan Avatar answered Sep 20 '22 09:09

Morgan