4

I was trying to connect to Google API through OAuth through JWT, but I keep getting this error:

{ "error": "invalid_grant", "error_description": "Invalid JWT: Token must be a short-lived token and in a reasonable timeframe" }

In my JWT calim I set the iat to be current time minus 1970-01-01 in seconds and exp to iat + 3600, so I do not know why I am still getting this error. If anyone knows the answer please tell meeeeee!

Linda Lawton - DaImTo
  • 106,405
  • 32
  • 180
  • 449
andy
  • 195
  • 1
  • 2
  • 15
  • 1
    Are you making your own JWT claim? time needs to be the current time NTP https://en.wikipedia.org/wiki/Network_Time_Protocol – Linda Lawton - DaImTo Apr 28 '16 at 08:32
  • thanks for the reply, I set the time to UTC and now I'm getting a invalid signature error, would you know what I am doing wrong? – andy Apr 28 '16 at 10:06
  • $sig = hash_hmac('sha256', utf8_encode($base64encodedHeaderAndPayload), "-----BEGIN PRIVATE KEY-----\n privatekey \n-----END PRIVATE KEY-----\n"); $signature = base64url_encode($sig); – andy Apr 28 '16 at 10:07
  • Note a clue I have also tried to create my own JWT token ever managed to get it to work http://stackoverflow.com/questions/33438494/google-service-account-authentication-with-json-file I use have been stuck using Googles client library's. What language are you using maybe you can pick apart the client library code. – Linda Lawton - DaImTo Apr 28 '16 at 10:10

5 Answers5

2

Not sure if you ever got it to work, but the following simple steps worked for me using the PHP function openssl_sign():

//helper function
function base64url_encode($data) { 
    return rtrim(strtr(base64_encode($data), '+/', '-_'), '='); 
}

//Google's Documentation of Creating a JWT: https://developers.google.com/identity/protocols/OAuth2ServiceAccount#authorizingrequests

//{Base64url encoded JSON header}
$jwtHeader = base64url_encode(json_encode(array(
    "alg" => "RS256",
    "typ" => "JWT"
)));
//{Base64url encoded JSON claim set}
$now = time();
$jwtClaim = base64url_encode(json_encode(array(
    "iss" => "761326798069-r5mljlln1rd4lrbhg75efgigp36m78j5@developer.gserviceaccount.com",
    "scope" => "https://www.googleapis.com/auth/prediction",
    "aud" => "https://www.googleapis.com/oauth2/v4/token",
    "exp" => $now + 3600,
    "iat" => $now
)));
//The base string for the signature: {Base64url encoded JSON header}.{Base64url encoded JSON claim set}
openssl_sign(
    $jwtHeader.".".$jwtClaim,
    $jwtSig,
    $your_private_key_from_google_api_console,
    "sha256WithRSAEncryption"
);
$jwtSign = base64url_encode($jwtSig);

//{Base64url encoded JSON header}.{Base64url encoded JSON claim set}.{Base64url encoded signature}
$jwtAssertion = $jwtHeader.".".$jwtClaim.".".$jwtSig;
Joseph Shih
  • 1,244
  • 13
  • 25
  • 1
    Sorry I kept forgetting to update this. This was indeed the right answer! Although I don't need to use this anymore because App Engine allows me to directly reach Cloud Storage now. But still thank you for the right answer! :) – andy Jun 05 '17 at 02:19
  • Hey @Joseph Shih I am having similar issue, my error is `Invalid JWT Signature.`. Can you share your POST request. I guess I'm having issues with `grant_type` in the request body. – Michel Jan 05 '18 at 03:50
  • @Michel, an invalid JWT signature error means that your signature failed to authenticate your $jwtHeader and $jwtClaim. Are you using the correct ISS (email address of the service account) and are you using the private key from your API console. Also, remember you'll need to base-64 encode the signature (like the example above). – Joseph Shih Jan 11 '18 at 22:56
  • 1
    Never mind @JosephShih I was able to fix it. I posted the answer here: https://stackoverflow.com/questions/48106432/invalid-signature-google-jwt-api Still thanks for the reply :) – Michel Jan 12 '18 at 11:24
2

I had the same issue, I solved it by syncing my VMs time to have the correct one with a public ntpserver:

ntpdate ntp.ubuntu.com
Sergio Gonzalez
  • 1,851
  • 1
  • 12
  • 12
1

You have to set a correct expiration time for the token if you see this error. Example:

var currentTime = new Date().getTime() / 1000; //must be in seconds
var exp = currentTime + 60;

var auth_claimset = {
      iss       :   "...",
      scope     :   "...",
      aud       :   "...",
      exp       :   exp,
      iat       :   currentTime 
};
lxknvlk
  • 2,744
  • 1
  • 27
  • 32
0

If you are following the steps under HTTP/Rest here: https://developers.google.com/identity/protocols/OAuth2ServiceAccount#formingheader, you'll see that your service accounts support RSA SHA-256, and you appear to use HMAC.

user2705223
  • 1,219
  • 6
  • 10
  • So I have modified to the below code: ' $sig = hash('SHA256', $headerAndPayload, $secret); $signature = base64url_encode($sig); $jwt = $headerAndPayload . "." . $signature; ' I keep getting a signature invalid for some reason. $secret is the private key i obtained from service account key json file. Would you know what's wrong? – andy Apr 29 '16 at 08:19
  • I just found out that using hash in PHP does not use a secret key, so I should probably still use hash_hmac, and I am not getting a result :/ – andy Apr 29 '16 at 08:43
  • There appear to be signing libraries that create spec compliant JWTs. For example: https://github.com/namshi/jose – user2705223 Apr 29 '16 at 17:44
0

This happens with WSL as well if you are doing testing on a local dev machine with WSL2 backend on Docker in Windows it will cause this problem.

You need to install ntpdate

sudo apt install ntpdate

Then you need to set the time.

sudo ntpdate time.windows.com

Good article about it here - https://tomssl.com/fixing-clock-drift-in-wsl2-using-windows-terminal/

Goddard
  • 2,863
  • 31
  • 37