简体   繁体   中英

“Invalid Grant Type” when Connecting to Google Service Account via Angular4

I've been wrecking my head around this problem and open to any guidance. I have a Angular 4 app where I am using Oauth to create access to a Google Cloud Datastore service account. I am using JWT and encoding it to pass to Google. Below is the function for the signature and the HTTP request.

I'm not sure if the encoding is incorrect or if I am trying to access the API incorrectly. Open to any suggetions on where I may have went wrong or a better way of doing this that does not involve piggy backing off of nodejs.

Function to get token below:

getGoogleToken(){

let key = this.createGoogleSig();
let params = {
  grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer',
  assertion: key
};

 let myheaders = new Headers;

 myheaders.append('Content-Type', 'application/x-www-form-urlencoded')

console.log(params);

this.http.post('https://www.googleapis.com/oauth2/v4/token', params, { headers : myheaders}).subscribe(
  data => this.thing = data.toString(),
  err => console.log(err),
  () => console.log('Request Complete')
);

}

The Code to create the signature

createGoogleSig(){

let now = (Date.now() / 1000).toFixed(0);
let exp = +now + 1800;

let key = {
  "type": "service_account",
  "project_id": "jenenginecms",
  "private_key_id": "---",
  "private_key": "-----BEGIN PRIVATE KEY-----cut for brevity---END PRIVATE KEY-----\n",
  "client_email": "pepperbirdcms@jenenginecms.iam.gserviceaccount.com",
  "client_id": "---",
  "auth_uri": "https://accounts.google.com/o/oauth2/auth",
  "token_uri": "https://accounts.google.com/o/oauth2/token",
  "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
  "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/pepperbirdcms%40jenenginecms.iam.gserviceaccount.com"
}




let claimObj = {
  "iss": key.client_email,
  "scope": "https://www.googleapis.com/auth/datastore",
  "aud": "https://www.googleapis.com/oauth2/v4/token",
  "exp": exp,
  "iat": +now
}
console.log(claimObj);

let header = Base64.encodeURI('{"alg":"RS256","typ":"JWT"}');

let claimSet = Base64.encodeURI(JSON.stringify(claimObj));

let sig = new KJUR.crypto.Signature({ "alg": "SHA256withRSA" });

let privateKey = key.private_key;



let ret = encryptSignature();

let jwt = header + "." + claimSet + "." + ret;

console.log(jwt)
return jwt;

function encryptSignature() {
  sig.init(privateKey);
  sig.updateString(header + "." + claimSet);
  let cleaned_hex = sig.sign()

  let input = new Array();
  for (let i = 0; i < cleaned_hex.length / 2; i++) {
    let h = cleaned_hex.substr(i * 2, 2);
    input[i] = parseInt(h, 16);
  }

  let base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"

  let ret = '';
  let i = 0;
  let j = 0;
  let char_array_3 = new Array(3);
  let char_array_4 = new Array(4);
  let in_len = input.length;
  let pos = 0;

  while (in_len--) {
    char_array_3[i++] = input[pos++];
    if (i == 3) {
      char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
      char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
      char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
      char_array_4[3] = char_array_3[2] & 0x3f;

      for (i = 0; (i < 4); i++)
        ret += base64_chars.charAt(char_array_4[i]);
      i = 0;
    }
  }

  if (i) {
    for (j = i; j < 3; j++)
      char_array_3[j] = 0;

    char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
    char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
    char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
    char_array_4[3] = char_array_3[2] & 0x3f;

    for (j = 0; (j < i + 1); j++)
      ret += base64_chars.charAt(char_array_4[j]);

    while ((i++ < 3))
      ret += '=';

  }
  return ret;
}

}

Actually the full error was quite helpful :)

Take this request for example:

POST https://www.googleapis.com/oauth2/v4/token HTTP/1.1
Host: www.googleapis.com
Content-type: application/x-www-form-urlencoded

grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer

When I perform this, I get

{
 "error": "invalid_request",
 "error_description": "Missing required parameter: assertion"
}

which is an error, but that' totally fine since it is a different error. It proves that Google recognizes this grant type. Now a look at your error message:

"error_description": "Invalid grant_type: "

The description string ends with a colon and a space. This is an indication that the server didn't receive a request body or couldn't interpret it. To prove this, I sent another request, this time with grant_type=thisdoesntexist and I got this:

{
 "error": "unsupported_grant_type",
 "error_description": "Invalid grant_type: thisdoesntexist"
}

That means that there is a flaw in your POST request. I can see two possible problems:

  1. The header is not set correctly. To use Content-type: application/x-www-form-urlencoded like you did is the right idea, but maybe the headers aren't correctly attached to your request?

  2. The request body isn't set correctly.

I advise you to double-check whether you implemented the this.http.post call correctly, especially the line data => this.thing = data.toString(), of which I have no idea what it is supposed to do.

If by doing that you don't find any mistakes you can try to monitor your request. For this you can either use a tool like Fiddler or you quickly set up a script on a local web-server that just echoes the headers and message body/POST parameters and call it inside your app, replacing https://www.googleapis.com/oauth2/v4/token .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM