Auth0 Home Blog Docs

Get google api token with user profile


#1

I’m wondering if I can set up my login using using the universal login and Auth0 PHP SDK so that for google logins I get a google api access token returned in the user profile. My current workflow is as follows:

The user logs in using universal login. When redirected, my PHP page then has to perform two tasks to get a google contacts token:

  1. a call is made to get an auth0 Access Token to call the Management API
  2. a call is made to the Management API to get the users google token

If there is a way that I can request the token to be included on first login my app would operate much faster. My current requested scopes are:

'scope' => 'profile openid email'

Which SDK does this apply to? (Ex: auth-node)
auth0/auth0-php
Which verison of the SDK you are using? (Ex: 1.0)
5.2.0 Auth0 PHP SDK.


#2

Yes, you can definitely do this, but it will require a bit of coding on your part.

You’re already on the right track with those scopes: you can do it with custom claims. Basically you write a rule that adds the Google token to your access or ID token (you’ll need to decide for yourself which one you want it in) and request it in your scopes.

An important note: to be OIDC compliant, the custom claim must be namespaced. So it could look like this: http://example.com/googleCalendarToken.

Hope that helps!


#3

@thijmen96 Thanks for the advice. This makes sense that I need to make my custom claim OIDC to prevent collisions. To get started with making this rule I am looking at preset rule examples and see two google related rules. (Store Google Refresh Token, Create a Google access_token using a Service Account) Do either of these give me a starting point to start coding this? It really seems like a common need for users to have a google api token returned in the user profile.


#4

OK, I’ve gotten halfway there looking at some previous posts. My rule can obtain a management token for the v2 api, but I cannot seem to get the google token from the user profile. Specifically, management.getUser isn’t returning a token like I expect. Here’s what I’ve got so far:

function(user, context, callback) {

    var ManagementClient = require('auth0@2.6.0').ManagementClient;
    var management = new ManagementClient({
        token: auth0.accessToken,
        domain: auth0.domain
    });

    // console.log(user.user_id);
    //*************************************
    var getApiv2AccessToken = function(domain, clientId, clientSecret, cb) {
        var cacheKey = clientId + '_token';
        var cachedToken = global[cacheKey];
        if (cachedToken && cachedToken.expirationDate > Date.now()) {
            // token is valid
            return cb(null, cachedToken.accessToken);
        }

        // token not present or expired, get a fresh one
        var request = require("request");
        var options = {
            method: 'POST',
            url: 'https://' + domain + '/oauth/token',
            body: {
                client_id: clientId,
                client_secret: clientSecret,
                audience: 'https://' + domain + '/api/v2/',
                grant_type: 'client_credentials'
            },
            json: true
        };

        request(options, function(error, response, body) {
            if (error) {
                console.log('Error getting access token for API v2.', error);
                return cb("Error getting access token: " + error);
            }
            global[cacheKey] = {
                accessToken: body.access_token,
                // 60 seconds safe window time
                expirationDate: Date.now() + (body.expires_in - 60) * 1000
            };
            return cb(null, body.access_token);
        });
    };

    getApiv2AccessToken(
        configuration.AUTH0_DOMAIN,
        configuration.APIV2_CLIENT_ID,
        configuration.APIV2_CLIENT_SECRET,
        function(err, accessToken) {
            if (err) {
                callback(err);
            }
            //console.log(accessToken);
            // now call the API v2 with the accessToken
            //
            //...
            // and continue
            var ManagementClient = require('auth0@2.6.0').ManagementClient;
            var management = new ManagementClient({
                token: accessToken,
                domain: auth0.domain,
                audience: 'https://ultrasoundjelly.auth0.com/api/v2/',
                tokenProvider: {
                    enableCache: true,
                    cacheTTLInSeconds: 10
                }
            });
            management.getUser({
                id: user.user_id
            }, function(err, user) {
                console.log(user);
                const namespace = 'https://www.sonoclipshare.com/';
                if (user.identities[0].access_token) {
                    context.idToken[namespace + 'access_token'] = user.identities[0].access_token;
                } else {
                    context.idToken[namespace + 'access_token'] = "null";
                }
            });
            callback(null, user, context);
        });
    //******************

    callback(null, user, context);
}

#5

Aha. Got the token, just had to change the scope to read:user_idp_tokens. Now I need to figure out how to pass the token through to the auth0 user profile…


#6

What do you mean with “pass the token through to the Auth0 user profile”? You mean storing it in either user_metadata or app_metadata? Or do you mean adding it to the ID or access token? I wouldn’t advice storing it in either user_metadata or app_metadata, as it’s already stored in another part of the Auth0 user profile (user.identities). Duplicating this kind of data doesn’t sound like a good idea here.


#8

I was hoping to store it in a way to be accessible with $auth0->getUser();
Dumping the contents doesn’t appear to contain the token. Is my approach incorrect?


#9

Ah, I see it now. Used $auth0->getIdToken(); to get the id_token and verified/decoded the JWT to get my value. Thanks.