Google-api-javascript-client: Google API Sign-In using auth2 fails with error: Refused to execute inline script because it violates the following Content Security Policy directive

Created on 31 Aug 2018  路  6Comments  路  Source: google/google-api-javascript-client

Hi,

This error may sometime happen, maybe roughly 1 in 10.
User clicks the Google Sign-In button, the Google Sign-In pops up and user authorize. An error is thrown and the sign-in fails.
The error:
Refused to execute inline script because it violates the following Content Security Policy directive: "script-src 'report-sample' 'nonce-zliYOlwerV1MslRE5pQXs8J5g' 'unsafe-inline' 'strict-dynamic' https: http: 'unsafe-eval'". Note that 'unsafe-inline' is ignored if either a hash or nonce value is present in the source list.

The codes used that throws the error:
Programmatically loading google api asynchronously from another external js file, for example:

// myscript.js
var d = document;
var t = 'script';
var o = d.createElement(t);
var s = d.getElementsByTagName(t)[0];
o.src = 'https://apis.google.com/js/api:client.js';
o.addEventListener('load', function(e) {
gapi.load('auth2', function() {
var a = gapi.auth2.init({
client_id: 'my-client-id.apps.googleusercontent.com',
scope : 'profile email'
});
a.isSignedIn.listen(function(v) {
// process sign-in state changes
});

                a.currentUser.listen(function(v) { 
                      // process changes to current user
                });

             document.getElementById('myCustomGoogleSignInButton').onclick = function() {
                 a.signIn();
             };
     });

}, false);

Most helpful comment

This error is still happening, maybe less often than it used too few months ago when the ticket was created, but we're still getting quite often blank login pages with the CSP error Refused to execute inline script because it violates the following Content Security Policy directive: "script-src 'report-sample' 'nonce-sN0Wr7kqJkMOZSPL6FK25Q' 'unsafe-inline' 'strict-dynamic' https: http: 'unsafe-eval'". Note that 'unsafe-inline' is ignored if either a hash or nonce value is present in the source list.

I captured the full request of this blank page (and I'm just using the usual way of loading gapi here).
The reason for the blank page is a mismatch in the nonce in the very last script element:

  • The nonce in the CSP header is sN0Wr7kqJkMOZSPL6FK25Q
  • The nonce in the last script element is ghywEpjAgyk81NFEYKG4LA, causing the error
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: Mon, 01 Jan 1990 00:00:00 GMT
Date: Mon, 31 Dec 2018 10:02:01 GMT
Content-Language: en-US
Content-Security-Policy: script-src 'report-sample' 'nonce-sN0Wr7kqJkMOZSPL6FK25Q' 'unsafe-inline' 'strict-dynamic' https: http: 'unsafe-eval';object-src 'none';base-uri 'self';report-uri /o/cspreport
Server: ESF
X-XSS-Protection: 1; mode=block
X-Frame-Options: SAMEORIGIN
Alt-Svc: quic=":443"; ma=2592000; v="44,43,39,35"
Content-Length: 1904

<!DOCTYPE html><html><head><title>Forwarding ...</title><meta http-equiv="content-type" content="text/html; charset=utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=0"><script src='https://ssl.gstatic.com/accounts/o/106854699-xsrfstatemanager.js' nonce="sN0Wr7kqJkMOZSPL6FK25Q"></script></head><body ><noscript><meta http-equiv="refresh" content="0;url=/o/noscript"></noscript>
<!-- framebuster code starts here -->
<style nonce="sN0Wr7kqJkMOZSPL6FK25Q">plaintext{display:none}</style>
<script nonce="sN0Wr7kqJkMOZSPL6FK25Q">
(function(){
try{
    var win=this;
    while("<plaintext>"){
       if(win.parent==win)
          break;
       eval("win.frameElement.src").substr(0,1);
       win=win.parent;
    }
    if(win.frameElement!=null)throw 'busted';
    document.write("\x3Cxmp style\x3Ddisplay:none\x3E");
}catch(e){
    try{
        if(!open(location,'_top'))
           alert('this content cant be framed');
   top.location=location;
    }catch(e){}
}
})();
</script>
<!-- do not remove the plaintext nor xmp tags -->
<plaintext/><xmp>.</xmp>
<!-- framebuster code ends here -->
<script type="text/javascript" nonce="ghywEpjAgyk81NFEYKG4LA">xsrfstatemanager.chooseKeyAndRedirect( 'https:\/\/accounts.google.com\/signin\/oauth?client_id\x3d428563709008-012cqlf90qe2o6nendt06vjn1mjkah4o.apps.googleusercontent.com\x26as\x3d2XjjxfsPvBS2OlF0OEQ6sg\x26nosignup\x3d1\x26destination\x3dhttps:\/\/gapi-auth2-cache-bug.glitch.me\x26approval_state\x3d!ChRjakotRng3UktrUGE3d08tNFVmUxIfSTRUdTRQSFRsZ1lUUUhVU2RlLXNqMHo3bTJnN2dCWQ%E2%88%99APNbktkAAAAAXCs6mTWZZjfWrTFuHimAHyjmf93Vgxux\x26oauthgdpr\x3d1\x26xsrfsig\x3dAHgIfE8X8vbNxkIRgVbxpoREpQPEfYNA7A', 'vqE7xRL5LA-oAS27E6HfB99-ZRlSzONgqZi1yLE1x28', 'OCAK',true, 'https:\/\/accounts.google.com\/o\/nocookie');</script></body></html>

By the way, there is a CSP report on the URL https://accounts.google.com/o/cspreport, you are probably getting tons of reports there:

{ "csp-report": { "document-uri": "https://accounts.google.com/o/oauth2/auth?response_type=permission%20id_token&scope=email%20profile%20https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fdrive&openid.realm=&prompt=select_account&redirect_uri=storagerelay%3A%2F%2Fhttps%2Fgapi-auth2-cache-bug.glitch.me%3Fid%3Dauth181711&client_id=428563709008-012cqlf90qe2o6nendt06vjn1mjkah4o.apps.googleusercontent.com&ss_domain=https%3A%2F%2Fgapi-auth2-cache-bug.glitch.me&gsiwebsdk=2", "referrer": "https://gapi-auth2-cache-bug.glitch.me/?client_id=428563709008-012cqlf90qe2o6nendt06vjn1mjkah4o.apps.googleusercontent.com&scope=email+profile+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fdrive&include_granted_scopes=false", "violated-directive": "script-src-elem", "effective-directive": "script-src-elem", "original-policy": "script-src 'report-sample' 'nonce-sN0Wr7kqJkMOZSPL6FK25Q' 'unsafe-inline' 'strict-dynamic' https: http: 'unsafe-eval';object-src 'none';base-uri 'self';report-uri /o/cspreport", "disposition": "enforce", "blocked-uri": "inline", "line-number": 28, "source-file": "https://accounts.google.com/o/oauth2/auth?response_type=permission%20id_token&scope=email%20profile%20https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fdrive&openid.realm=&prompt=select_account&redirect_uri=storagerelay%3A%2F%2Fhttps%2Fgapi-auth2-cache-bug.glitch.me%3Fid%3Dauth181711&client_id=428563709008-012cqlf90qe2o6nendt06vjn1mjkah4o.apps.googleusercontent.com&ss_domain=https%3A%2F%2Fgapi-auth2-cache-bug.glitch.me&gsiwebsdk=2", "status-code": 0, "script-sample": "xsrfstatemanager.chooseKeyAndRedirect( '" } }

This longstanding issue is getting really annoying, and causing various reports from our customers as well. Is anyone at Google looking into it?

All 6 comments

Try to disable any extensions like AdBlock or Ghostery

On my login page, I get this error in Safari (with no extensions) even before the user clicks Sign In:

The source list for Content Security Policy directive 'script-src' contains an invalid source: ''strict-dynamic''. It will be ignored.

This error is still happening, maybe less often than it used too few months ago when the ticket was created, but we're still getting quite often blank login pages with the CSP error Refused to execute inline script because it violates the following Content Security Policy directive: "script-src 'report-sample' 'nonce-sN0Wr7kqJkMOZSPL6FK25Q' 'unsafe-inline' 'strict-dynamic' https: http: 'unsafe-eval'". Note that 'unsafe-inline' is ignored if either a hash or nonce value is present in the source list.

I captured the full request of this blank page (and I'm just using the usual way of loading gapi here).
The reason for the blank page is a mismatch in the nonce in the very last script element:

  • The nonce in the CSP header is sN0Wr7kqJkMOZSPL6FK25Q
  • The nonce in the last script element is ghywEpjAgyk81NFEYKG4LA, causing the error
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: Mon, 01 Jan 1990 00:00:00 GMT
Date: Mon, 31 Dec 2018 10:02:01 GMT
Content-Language: en-US
Content-Security-Policy: script-src 'report-sample' 'nonce-sN0Wr7kqJkMOZSPL6FK25Q' 'unsafe-inline' 'strict-dynamic' https: http: 'unsafe-eval';object-src 'none';base-uri 'self';report-uri /o/cspreport
Server: ESF
X-XSS-Protection: 1; mode=block
X-Frame-Options: SAMEORIGIN
Alt-Svc: quic=":443"; ma=2592000; v="44,43,39,35"
Content-Length: 1904

<!DOCTYPE html><html><head><title>Forwarding ...</title><meta http-equiv="content-type" content="text/html; charset=utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=0"><script src='https://ssl.gstatic.com/accounts/o/106854699-xsrfstatemanager.js' nonce="sN0Wr7kqJkMOZSPL6FK25Q"></script></head><body ><noscript><meta http-equiv="refresh" content="0;url=/o/noscript"></noscript>
<!-- framebuster code starts here -->
<style nonce="sN0Wr7kqJkMOZSPL6FK25Q">plaintext{display:none}</style>
<script nonce="sN0Wr7kqJkMOZSPL6FK25Q">
(function(){
try{
    var win=this;
    while("<plaintext>"){
       if(win.parent==win)
          break;
       eval("win.frameElement.src").substr(0,1);
       win=win.parent;
    }
    if(win.frameElement!=null)throw 'busted';
    document.write("\x3Cxmp style\x3Ddisplay:none\x3E");
}catch(e){
    try{
        if(!open(location,'_top'))
           alert('this content cant be framed');
   top.location=location;
    }catch(e){}
}
})();
</script>
<!-- do not remove the plaintext nor xmp tags -->
<plaintext/><xmp>.</xmp>
<!-- framebuster code ends here -->
<script type="text/javascript" nonce="ghywEpjAgyk81NFEYKG4LA">xsrfstatemanager.chooseKeyAndRedirect( 'https:\/\/accounts.google.com\/signin\/oauth?client_id\x3d428563709008-012cqlf90qe2o6nendt06vjn1mjkah4o.apps.googleusercontent.com\x26as\x3d2XjjxfsPvBS2OlF0OEQ6sg\x26nosignup\x3d1\x26destination\x3dhttps:\/\/gapi-auth2-cache-bug.glitch.me\x26approval_state\x3d!ChRjakotRng3UktrUGE3d08tNFVmUxIfSTRUdTRQSFRsZ1lUUUhVU2RlLXNqMHo3bTJnN2dCWQ%E2%88%99APNbktkAAAAAXCs6mTWZZjfWrTFuHimAHyjmf93Vgxux\x26oauthgdpr\x3d1\x26xsrfsig\x3dAHgIfE8X8vbNxkIRgVbxpoREpQPEfYNA7A', 'vqE7xRL5LA-oAS27E6HfB99-ZRlSzONgqZi1yLE1x28', 'OCAK',true, 'https:\/\/accounts.google.com\/o\/nocookie');</script></body></html>

By the way, there is a CSP report on the URL https://accounts.google.com/o/cspreport, you are probably getting tons of reports there:

{ "csp-report": { "document-uri": "https://accounts.google.com/o/oauth2/auth?response_type=permission%20id_token&scope=email%20profile%20https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fdrive&openid.realm=&prompt=select_account&redirect_uri=storagerelay%3A%2F%2Fhttps%2Fgapi-auth2-cache-bug.glitch.me%3Fid%3Dauth181711&client_id=428563709008-012cqlf90qe2o6nendt06vjn1mjkah4o.apps.googleusercontent.com&ss_domain=https%3A%2F%2Fgapi-auth2-cache-bug.glitch.me&gsiwebsdk=2", "referrer": "https://gapi-auth2-cache-bug.glitch.me/?client_id=428563709008-012cqlf90qe2o6nendt06vjn1mjkah4o.apps.googleusercontent.com&scope=email+profile+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fdrive&include_granted_scopes=false", "violated-directive": "script-src-elem", "effective-directive": "script-src-elem", "original-policy": "script-src 'report-sample' 'nonce-sN0Wr7kqJkMOZSPL6FK25Q' 'unsafe-inline' 'strict-dynamic' https: http: 'unsafe-eval';object-src 'none';base-uri 'self';report-uri /o/cspreport", "disposition": "enforce", "blocked-uri": "inline", "line-number": 28, "source-file": "https://accounts.google.com/o/oauth2/auth?response_type=permission%20id_token&scope=email%20profile%20https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fdrive&openid.realm=&prompt=select_account&redirect_uri=storagerelay%3A%2F%2Fhttps%2Fgapi-auth2-cache-bug.glitch.me%3Fid%3Dauth181711&client_id=428563709008-012cqlf90qe2o6nendt06vjn1mjkah4o.apps.googleusercontent.com&ss_domain=https%3A%2F%2Fgapi-auth2-cache-bug.glitch.me&gsiwebsdk=2", "status-code": 0, "script-sample": "xsrfstatemanager.chooseKeyAndRedirect( '" } }

This longstanding issue is getting really annoying, and causing various reports from our customers as well. Is anyone at Google looking into it?

I think I found a solution. CSP by default blocks any loading of scripts or styles from JavaScript. The JavaScript for Google API Sign In loads both scripts and styles, which causes the problem.

To allow it to do so, the easiest thing to do is add 'unsafe-inline' to the script-src and style-src directives of the CSP. This should only be temporary because it allows _all_ inline scripts to be executed.

Instead, a nonce (number once) should be used where necessary. This, according to the CSP reference, "allows script or style tag to execute if the nonce attribute value matches the header value."

For example, to allow inlineTest.js, you would randomly generate a nonce (on every request), random123 in this case. The nonce then must be added to the CSP.

HTML: <script src="inlineTest.js" nonce=random123></script>
CSP: script-src 'nonce-random123'

Most frameworks with template systems should have an option to do this automatically. With Play Framework, a special string added to a template causes the engine to insert a nonce and add it to the source list. Instead of using a predefined CSP, Play Framework generates a CSP with all of the nonces.

W3 recommends removing any inline code, so Google should be prioritizing a fix for this. Maybe they could include whatever code they load in the same script that we already load.

@grant as the most active / recent contributor to this repo, what's the latest on this issue? Can you point someone in its direction within Google?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

dominikstrasser picture dominikstrasser  路  4Comments

Price775 picture Price775  路  3Comments

mesqueeb picture mesqueeb  路  5Comments

nidri picture nidri  路  7Comments

wonderfly picture wonderfly  路  5Comments