Obtain an id token in the Gmail add-on for a backend service authentication
Asked Answered
B

2

11

The background
I'm using the Google Apps Script to create a Gmail Add-on. Via this plugin, I would like to connect to my backend server (a non-Google service) using a REST service request. The request has to be authorised. When authorised, I could then make requests to that server to receive data associated with that user in the database. I'm already using Google sign-in in my webapp to sign in to the backend service - at the front end, I receive the id_token inside of the GoogleUser object in the authorisation response.

The problem
I need this id_token to log in to my backend service when connecting to it via the Gmail plugin. However, I couldn't find a way how to access the token.

The research
I would assume the token must be available through the API in the Apps Script.
In the webapp, I receive the id_token using the Google Auth API like this:

Promise.resolve(this.auth2.signIn())
        .then((googleUser) => {
            let user_token = googleUser.getAuthResponse().id_token; // this is the id_token I need in the Gmail plugin, too

            // send the id_token to the backend service
            ...
        };

In the Google Apps Script API I could only find the OAuth token:

ScriptApp.getOAuthToken();

I assumed the token could also be stored in the session. The Google Apps Script API contains the Session class and that itself contains the getActiveUser method, which returns the User object. The User object, however, only contains the user's email address, no id token (or anything else for that matter):

Session.getActiveUser().getEmail();


The question(s)
Is there a way to obtain the id token?
Am I choosing the right approach to logging in to the backend server using the data of the signed-in user in the Gmail?

Belk answered 18/9, 2018 at 13:36 Comment(5)
For example, when you set onTriggerFunction to buildAddOn in appsscript.json, you can retrieve the access token by e.messageMetadata.accessToken from e of function buildAddOn(e){}. If this was not what you want, I'm sorry.Sumptuous
Not quite. This is the access token, I need to acquire the id token. But thank you.Euratom
I'm really sorry I misunderstood your question.Sumptuous
What do you do with the id_token? Do you only read sub?Diggings
I would like to use the id_token to enable my own server to make requests to Gmail on my behalf. The same way you do when you log in to Gmail via Google OAuth login. But in this case I'm already logged in to Gmail (as a user of the Gmail add-on I have to be). And I would like to use that session information to enable my server to access my account data (messages, profile information etc.).Euratom
F
6

Method 1: use getIdentityToken()

Gets an OpenID Connect identity token for the effective user:

var idToken = ScriptApp.getIdentityToken();
var body = idToken.split('.')[1];
var decoded = Utilities.newBlob(Utilities.base64Decode(body)).getDataAsString();
var payload = JSON.parse(decoded);
var profileId = payload.sub;
Logger.log('Profile ID: ' + profileId);

Method 2: use Firebase and getOAuthToken()

Steps to get Google ID Token from Apps Script's OAuth token:

  1. Enable Identity Toolkit API for your Apps Script project.
  2. Add new Firebase project to your existing Google Cloud Platform project at https://console.firebase.google.com/
  3. Create Firebase app for platform: Web.
  4. You will get your config data: var firebaseConfig = {apiKey: YOUR_KEY, ...}.
  5. Enable Google sign-in method for your Firebase project at https://console.firebase.google.com/project/PROJECT_ID/authentication/providers.
  6. Use Apps Script function to get ID Token for current user:

function getGoogleIDToken()
{
    // get your configuration from Firebase web app's settings
    var firebaseConfig = {
        apiKey: "***",
        authDomain: "*.firebaseapp.com",
        databaseURL: "https://*.firebaseio.com",
        projectId: "***",
        storageBucket: "***.appspot.com",
        messagingSenderId: "*****",
        appId: "***:web:***"
    };

    var res = UrlFetchApp.fetch('https://identitytoolkit.googleapis.com/v1/accounts:signInWithIdp?key='+firebaseConfig.apiKey, {
        method: 'POST',
        payload: JSON.stringify({
            requestUri: 'https://'+firebaseConfig.authDomain,
            postBody: 'access_token='+ScriptApp.getOAuthToken()+'&providerId=google.com',
            returnSecureToken: true,
            returnIdpCredential: true
        }),
        contentType: 'application/json',
        muteHttpExceptions: true
    });

    var responseData = JSON.parse(res);

    idToken = responseData.idToken;

    Logger.log('Google ID Token: ');
    Logger.log(idToken);

    return idToken;
}

Kudos to Riël Notermans

Fons answered 5/2, 2020 at 16:54 Comment(1)
In the Method 1 above, once you have the idToken in the add-on, what is the right way to use it to authorize with your RESTful backend? i.e. would you have some sort of token exchange endpoint that takes in the idToken and returns a bearer token that can be used with your own endpoint? And that exchange endpoint would validate the idToken?Abstinence
C
1

You should enable oAuth scopes, https://developers.google.com/apps-script/concepts/scopes

Cauda answered 14/12, 2018 at 16:22 Comment(2)
I already did that. I have these enabled: "googleapis.com/auth/gmail.addons.execute", "googleapis.com/auth/gmail.readonly", "googleapis.com/auth/gmail.addons.current.message.readonly", "googleapis.com/auth/userianfo.email", "googleapis.com/auth/script.locale", "googleapis.com/auth/script.external_request". But I don't see how that gives me the ID token. I'm missing some API method here, not a permission.Euratom
The required scope to get the userIdToken is "openid".Noami

© 2022 - 2024 — McMap. All rights reserved.