Generate an OAuth access token with openssl and c++

时间:2021-02-20 18:23:54

I need to get an access token (for a service account) for the google's OAuth authentication service. I tried several things an studied a lot of on the web but don't succeed.

我需要为Google的OAuth身份验证服务获取访问令牌(针对服务帐户)。我在网上尝试过很多东西,但没有成功。

Basically i followed https://developers.google.com/accounts/docs/OAuth2ServiceAccount

基本上我遵循https://developers.google.com/accounts/docs/OAuth2ServiceAccount

What i have done (VS2013):

我做了什么(VS2013):

int _tmain(int argc, _TCHAR* argv[])
{
    Json::Value jwt_header;
    Json::Value jwt_claim_set;
    std::string jwt_b64;
    std::time_t t = std::time(NULL);
    Json::FastWriter jfw;
    Json::StyledWriter jsw;

    /* Create jwt header */
    jwt_header["alg"] = "RS256";
    jwt_header["typ"] = "JWT";
    std::cout << jsw.write(jwt_header);

    /* Create jwt claim set */
    jwt_claim_set["iss"] = "myid@developer.gserviceaccount.com"; /* service account email address */
    jwt_claim_set["scope"] = "https://www.googleapis.com/auth/plus.me" /* scope of requested access token */;
    jwt_claim_set["aud"] = "https://accounts.google.com/o/oauth2/token"; /* intended target of the assertion for an access token */
    jwt_claim_set["iad"] = std::to_string(t); /* issued time */
    jwt_claim_set["exp"] = std::to_string(t+3600); /* expire time*/
    std::cout << jsw.write(jwt_claim_set);

    /* create http POST request body */
    /* for header */
    std::string json_buffer;
    std::string json_buffer1;
    json_buffer = jfw.write(jwt_header);
    json_buffer = json_buffer.substr(0, json_buffer.size() - 1);
    json_buffer = base64_encode(reinterpret_cast<const unsigned char*>(json_buffer.c_str()), json_buffer.length(), true); /* urlsafeBasic64 encode*/
    json_buffer1.clear();
    std::remove_copy(json_buffer.begin(), json_buffer.end(), std::back_inserter(json_buffer1), '=');
    jwt_b64 = json_buffer1;
    jwt_b64 += ".";

    /* for claim set */
    json_buffer = jfw.write(jwt_claim_set);
    json_buffer = json_buffer.substr(0, json_buffer.size() - 1);
    json_buffer = base64_encode(reinterpret_cast<const unsigned char*>(json_buffer.c_str()), json_buffer.length(), true); /* urlsafeBasic64 encode*/
    json_buffer1.clear();
    std::remove_copy(json_buffer.begin(), json_buffer.end(), std::back_inserter(json_buffer1), '=');
    jwt_b64 += json_buffer1;


    /* for signature */
    std::string jwt_signature = jws_sign(jwt_b64, "key.p12");
    if (!jwt_signature.empty())
    {
        jwt_b64 += ".";
        json_buffer1.clear();
        std::remove_copy(jwt_signature.begin(), jwt_signature.end(), std::back_inserter(json_buffer1), '=');
        jwt_b64 += json_buffer1;
        write2file("jwt.bat", jwt_b64); /* for test purpose calling with curl */
    }
    else
        std::cout << "Error creating signature";

    return 0;
}

int write2file(std::string filename, std::string data)
{
    std::ofstream f(filename);
    f << "%curl% -d \"grant_type=urn%%3Aietf%%3Aparams%%3Aoauth%%3Agrant-type%%3Ajwt-bearer&assertion=";
    f << data;
    f << "\" https://accounts.google.com/o/oauth2/token";
    f.close();
    return 0;
}

std::string jws_sign(std::string data, std::string pkcs12_path) {

    SHA256_CTX mctx;
    unsigned char hash[SHA256_DIGEST_LENGTH];
    size_t hlen = SHA256_DIGEST_LENGTH;
    const char *buf = data.c_str();
    int n = strlen((const char*) buf);

    SHA256_Init(&mctx);
    SHA256_Update(&mctx, buf, n);
    SHA256_Final(hash, &mctx);

    std::string signature_b64;
    unsigned char *sig = NULL;
    size_t slen = 0;
    EVP_PKEY_CTX *kctx;
    EVP_PKEY *key = getPkey(pkcs12_path);
    kctx = EVP_PKEY_CTX_new(key, NULL);
    if (!kctx) goto err;

    if (EVP_PKEY_sign_init(kctx) <= 0) goto err;

    if (EVP_PKEY_CTX_set_rsa_padding(kctx, RSA_PKCS1_PADDING) <= 0) goto err;

    if (EVP_PKEY_CTX_set_signature_md(kctx, EVP_sha256()) <= 0) goto err;

    /* Determine buffer length */
    if (EVP_PKEY_sign(kctx, NULL, &slen, hash, hlen) <= 0) goto err;

    sig = (unsigned char *) OPENSSL_malloc(slen);

    if (!sig) goto err;

    if (EVP_PKEY_sign(kctx, sig, &slen, hash, hlen) <= 0) goto err;

    signature_b64 = base64_encode(sig, (unsigned int)slen, true);

    return signature_b64;

err:

    /* Clean up */
    EVP_cleanup();

    signature_b64.clear();
    return signature_b64;
}

All i receive back is

我收到的全部是

{
  "error" : "invalid_grant"
}

So if someone can point me into the right direction would be great. It would also help, if someone can point me to get the thing working by manually generating the jwt request out of openssl commands.

所以如果有人能指出我正确的方向会很棒。如果有人可以通过手动生成openssl命令的jwt请求来指示我工作,那也会有所帮助。

I'm working with VS2013

我正在使用VS2013

1 个解决方案

#1


1  

I found my mistake - was simply a typo :(

我发现了我的错误 - 只是一个错字:(

jwt_claim_set["iad"] = std::to_string(t); /* issued time */

needs to be

需要是

jwt_claim_set["iat"] = std::to_string(t); /* issued time */

The code works and generate valid token requests.

代码工作并生成有效的令牌请求。

#1


1  

I found my mistake - was simply a typo :(

我发现了我的错误 - 只是一个错字:(

jwt_claim_set["iad"] = std::to_string(t); /* issued time */

needs to be

需要是

jwt_claim_set["iat"] = std::to_string(t); /* issued time */

The code works and generate valid token requests.

代码工作并生成有效的令牌请求。