Azure Functions Easy Auth & Google Access token

788 views Asked by At

I'm trying to add Google authentication to my Azure Functions app which will be used from a Svelte static web app (SWA). The SWA uses Google Identity (https://accounts.google.com/gsi/client) to both authenticate and then retrieve an access_token. Authentication is performed using a standard Google Identity sign in button. I've tried One Tap prompt as well with the same result.

google.accounts.id.initialize({
    client_id: googleClientId,
    callback: handleCredentialResponse,
});

google.accounts.id.renderButton(
    button,
    { theme: 'outline', size: 'large' }, // customization attributes
);

User authenticates, works fine and I get a JWT id_token containing name email image etcetera. It's a bit annoying the user has to then again go through the whole process of selecting their account, but I guess that's the Google experience. Once I'm ready to do function calls I then proceed to authorize:

function getAccessToken() {
    return new Promise((resolve, reject) => {
        const client = google.accounts.oauth2.initTokenClient({
            client_id: googleClientId,
            scope: "openid",
            callback: (response) => {
                if (response.access_token) {
                    resolve(access_token);
                } else {
                    reject(response?.error);
                }
            },
        });
        client.requestAccessToken();
    });
}

This also works fine, I retrieve an access_token. I then proceed to call an Azure Function with this token in the header:

Authorization: Bearer <ACCESS_TOKEN>

This always results in a 401 response. I have tried setting all functions to anonymous to no effect.

I'm wondering if this has to do with scope. In the Google Console it's only possible to add Google specific scopes, which is why I retrieve an access_token for the openid scope.

I've also tried setting credentials to include since there might be cookies the Easy Auth layer would like to read from the web app to authenticate the user. CORS on the Azure Functions app is configured correctly for the host names used by the web app and Access-Control-Allow-Credentials is enabled on the Function App. This has no effect either.

1

There are 1 answers

0
Wouter On

Wow this was badly documented. After reading the Azure Functions and App Service Authentication blog post it seems an 'authentication token' needs to be retrieved from the functions app itself instead of an 'access token' from Google. After Google identification the id_token from the first step needs to be POSTed to https://<functions_app>/.auth/login/google with the following as body:

{
  "id_token": "<id_token>"
}

This in turn returns something as follows:

{
  "authenticationToken": "<authenticationToken>",​
  "user": { "userId": "<sid>" }
}

This authenticationToken then needs be be passed in the header to each function call as follows:

X-ZUMO-AUTH: <authenticationToken>

Edit: it seems this was fully documented, somehow I missed this.