1

I am looking to set up authentication on an S3 hosted static site. The configuration is:

"request": {
    "clientIp": "abc.abc.abc.abc",
    "headers": {
        "host": [
            {
                "key": "Host",
                "value": "static-site.example.com"
            }
        ],
        "user-agent": [
            {
                "key": "User-Agent",
                "value": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:65.0) Gecko/20100101 Firefox/65.0"
            }
        ],
        "accept": [
            {
                "key": "Accept",
                "value": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8"
            }
        ],
        "accept-language": [
            {
                "key": "Accept-Language",
                "value": "en-GB,en;q=0.5"
            }
        ],
        "accept-encoding": [
            {
                "key": "Accept-Encoding",
                "value": "gzip, deflate, br"
            }
        ],
        "dnt": [
            {
                "key": "DNT",
                "value": "1"
            }
        ],
        "cookie": [
            {
                "key": "Cookie",
                "value": "G_ENABLED_IDPS=google; G_AUTHUSER_H=0"
            }
        ],
        "pragma": [
            {
                "key": "Pragma",
                "value": "no-cache"
            }
        ],
        "cache-control": [
            {
                "key": "Cache-Control",
                "value": "no-cache"
            }
        ]
    },
    "method": "GET",
    "querystring": "",
    "uri": "/"
}

The aim for the workflow is to require as little as possible logic in the lambda itself and as little as possible extra configuriton to the static html files served from the bucket. The auth backend we need is Google (any user with a valid @domain.example.com gmail address is allowed to access the site).

Following this guide https://developers.google.com/identity/sign-in/web/sign-in

I have been able to add client side auth to the webpage, e.g.:

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8" />
    <title>Page Title</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <script src="https://apis.google.com/js/platform.js" async defer></script>
    <meta name="google-signin-client_id" content="466912284544-tllqihp9bhk8aa29r8pmcgn51vld817r.apps.googleusercontent.com">
    <script>
        function onSignIn(googleUser) {
            var profile = googleUser.getBasicProfile();
            var id_token = googleUser.getAuthResponse().id_token;
            console.log('ID: ' + profile.getId()); // Do not send to your backend! Use an ID token instead.
            console.log('Name: ' + profile.getName());
            console.log('Image URL: ' + profile.getImageUrl());
            console.log('Email: ' + profile.getEmail()); // This is null if the 'email' scope is not present. 
        }
    </script>
</head>

<body>
    <div class="g-signin2" data-onsuccess="onSignIn"></div> 
</body>

</html>

This works great and the google agent manages all local session state.

The next step is to be able to send a token to the lambda to verify the user is authenticated before returning the private S3 content.

This page: https://developers.google.com/identity/sign-in/web/backend-auth

Provides an option to send a POST using javascript, adding the ID Token as a header and gives an example of the logic I would need to put in my Lambda to verify the token and the user's email address domain.

var xhr = new XMLHttpRequest();
xhr.open('POST', 'https://yourbackend.example.com/tokensignin');
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.onload = function() {
  console.log('Signed in as: ' + xhr.responseText);
};
xhr.send('idtoken=' + id_token);

If my understanding of this is correct everything should work as desired, however the sample code seems to be focussed on sending a one-off POST using javascript to auth with the backend whereas I would like to auth every GET request.

It seems like this would be possible if I add the ID token header to every GET request however this is a significant modification to the static HTML pages in my bucket (wrapping every URL with JS call).

My next thought was to have the onSignIn function save the user's ID Token as a cookie that would be visible to the Lambda on every request. I have done quite a bit of reading about this and there seems to be some conflicting advice on whether this is secure or not and even what exactly the ID token is.

I also looked at the alternative server-side auth pattern that google suggest but this seems to put the entire onus of session management on the server side code which is not viable with the simple Lambda@Edge model.

TL~DR

The questions are:

  • Is the google "ID token" the same as an OpenID Connect ID Token?
  • Is it okay to use this token to verify a user's identity?
  • Is it okay to save the Google ID Token in a cookie?
  • If not is there an alternative?
  • Is this workflow/tech stack viable at all or will I need some kind of server side session manager?

Cheers

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.