dreamevil0002 2016-06-28 14:55
浏览 242

PHP Google API OAuth2 JWT对新访问令牌的请求显示“invalid_grant”

In short, I want to obtain a new acces token with a service account on Google API. I used OAuth 2.0 and a JWT request. I found many similar post, but non of them answered my question. I done everything conform to the Google OAuth 2.0 Server-to-Server request guide, but when i send the POST request, i get in return "invalid_grant". Any ideas why? Here is my code:

$jwt_header_array =     array(  "alg"       => "RS256",
                                    "typ"       => "JWT");

    $jwt_claim_array =      array(  "iss"       => "upload-file@feedking-1355.iam.gserviceaccount.com",
                                    "scope"     => "https://www.googleapis.com/auth/drive.file",
                                    "aud"       => "https://www.googleapis.com/oauth2/v4/token",
                                    "exp"       => time()+3600,
                                    "iat"       => time());

    $jwt_header = base64_encode(json_encode($jwt_header_array));
    $jwt_claim = base64_encode(json_encode($jwt_claim_array));

    $key = "-----BEGIN PRIVATE KEY----- privat_key_downloaded_from_google_console -----END PRIVATE KEY-----
";

    $pkeyid = openssl_pkey_get_private($key);
    openssl_sign($jwt_header.'.'.$jwt_claim, $jwt_signature, $pkeyid, "sha256");
    $jwt_signature = base64_encode($jwt_signature);

    $jwt = $jwt_header.'.'.$jwt_claim.'.'.$jwt_signature;

    echo $jwt.'<br /><br />';

    $url = 'https://www.googleapis.com/oauth2/v4/token';
    $query = 'grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion='.$jwt;

    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/x-www-form-urlencoded'));
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
    curl_setopt($ch, CURLOPT_POST, 1);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $query);
    $result = curl_exec($ch);

    var_dump($result);
  • 写回答

1条回答 默认 最新

  • douju4594 2016-06-29 09:00
    关注

    I've found a solution, and it was ridiculously obvious. Why not using Google Utils, Auth and Signer/P12 classes? You can get the whole package with composer (google/apiclient), beside you will need this for making Google API authentication (in fact i already had this package, dumb me). I will guide you through the whole process:

    NEW SOLUTION:

    You will need the Google API package and the Google Service account as described in the old solution below (stage 1, 2, 3). From here just copy-paste the fully API based code and replace the input datas:

    $client_email = 'file-upload-final@feedking-1355.iam.gserviceaccount.com';
    $private_key = file_get_contents('p12_final.p12');
    $scopes = array('https://www.googleapis.com/auth/drive.file');
    $credentials = new Google_Auth_AssertionCredentials(
        $client_email,
        $scopes,
        $private_key
    );
    
    $client = new Google_Client();
    $client->setAssertionCredentials($credentials);
    if ($client->getAuth()->isAccessTokenExpired()) {
         $client->getAuth()->refreshTokenWithAssertion();
    }
    

    OLD SOLUTION:

    1. Create a Google Service account, since this is essential to access Google APIs without further user consent. Make sure that when you create it, you check "Furnish new private key" and "P12" options. Check other options as well if needed.

    2. Download, upload the P12 file to your server / local, and store the password (its usually "notasecret" at this time...).

    3. Install the Google API package with composer or GIT, if you don't have already. I prefer composer because the GIT version lacks some libraries, for me the Client class was a bit buggy (could be my fault of course).

    4. You just have to use the right classes to make and encode the JWT header and playload, and sign the certificate. Take care of the P12 certificate path and for the corrent inputs in the playload (you can get all of it from the Google Developer Console Credetials page, and you can also get informations about values on Google OAuth 2.0 Server-to-Server Application page). Here is the code:

    $header = array("typ" => "JWT", 
                    "alg" => "RS256");
    
    $playload = array(  "iss"       => "upload-file2@feedking-1355.iam.gserviceaccount.com", 
                        "scope"     => "https://www.googleapis.com/auth/drive.file",
                        "aud"       => "https://www.googleapis.com/oauth2/v4/token",
                        "exp"       => time()+3600,
                        "iat"       => time());
    
    $segments = array();
    $segments[] = Google_Utils::urlSafeB64Encode(json_encode($header));
    $segments[] = Google_Utils::urlSafeB64Encode(json_encode($playload));
    $signing_input = implode(".", $segments);
    $signer = new Google_Signer_P12(file_get_contents('p12.p12', true), 'notasecret');
    $signature = $signer->sign($signing_input);
    $segments[] = Google_Utils::urlSafeB64Encode($signature);
    $jwt = implode(".", $segments);
    
    1. Send the request with cURL or whatever you want to get the Access token:
    $url = 'https://www.googleapis.com/oauth2/v4/token';
    $query = 'grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion='.$jwt;
    
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/x-www-form-urlencoded'));
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
    curl_setopt($ch, CURLOPT_POST, 1);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $query);
    $result = curl_exec($ch);
    
    1. Finally the var_dump($result) output should be something similar:

    string(141) "{ "access_token": "ya29.Ci8QAzKz-U83RiaylDKgSDgH9XEVQrdBAQ5EBxMFUncN7WLfeGan0BCMJRdFJykC-g", "token_type": "Bearer", "expires_in": 3600 } "

    Hope you enjoyed it and will upvote, since i messed up 2 days with this authentication story. Google API can do magic in some cases, so it's an essential thing to learn inmho.

    评论

报告相同问题?

悬赏问题

  • ¥100 关于使用MATLAB中copularnd函数的问题
  • ¥20 在虚拟机的pycharm上
  • ¥15 jupyterthemes 设置完毕后没有效果
  • ¥15 matlab图像高斯低通滤波
  • ¥15 针对曲面部件的制孔路径规划,大家有什么思路吗
  • ¥15 钢筋实图交点识别,机器视觉代码
  • ¥15 如何在Linux系统中,但是在window系统上idea里面可以正常运行?(相关搜索:jar包)
  • ¥50 400g qsfp 光模块iphy方案
  • ¥15 两块ADC0804用proteus仿真时,出现异常
  • ¥15 关于风控系统,如何去选择