rgd_dev
rgd_dev

Reputation: 53

Cannot authenticate in Google OAuth2.0 for server to server applications

I'm trying to set up the Google OAuth authentication so I could get an access token for an account service and I could use other services through REST API such as Cloud Storage. Problem is that I get an 400 error when I make the access token request and the message is generic so I can't know what's not working. I'm using Typescript, Node, and some packages such as jsonwebtokens or jwt-simple for signing the JWT.

Any ideas if I'm missing something?

import moment from 'moment';
import jwt from 'jwt-simple';
import jsonwebtoken from 'jsonwebtoken'; // try wuth this one for signing the JWT too but same result
import axios from 'axios';
import base64Url from 'base64url';

export const authentication = function (): void {
    const nowInUnix = moment().unix();
    const secret = 'MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCc9HWEZ2VtoIt5...........';
    //this's supposed to be my private key so I removed the beginning and end from it 'cause in the file from where i get it was like this: "private_key": "-----BEGIN PRIVATE KEY-----MY_KEY-----END PRIVATE KEY-----\n"

    let header = { "alg": "RS256", "typ": "JWT" };
    const headerEncoded = base64Url.encode(JSON.stringify(header));
    let claims = {
        "iss": "[email protected]",
        "scope": "https://www.googleapis.com/auth/devstorage.full_control",
        "aud": "https://oauth2.googleapis.com/token",
        "exp": nowInUnix + 2000,
        "iat": nowInUnix
    };
    const claimsEncoded = base64Url.encode(JSON.stringify(claims));
    // console.log(claimsEncoded);
    const stringToEncrypt = headerEncoded + '.' + claimsEncoded;
    // console.log(stringToEncrypt);
    const signature = jwt.encode(stringToEncrypt, secret);
    // console.log(signature);
    const fullToken = headerEncoded + '.' + claimsEncoded + '.' + signature;
    console.log(fullToken);

    // Something else i don't know if how to pass the params, I assumed it's like query params but I also tried sending the in the body request and same result.
    axios.post(`https://oauth2.googleapis.com/token?grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion=${fullToken}`)
        .then(res => console.log('todo ok'))
        .catch(e => console.log(e));
}

This is the error I get: BAD_REQUEST: 400 screenshot of the error i see

Google Docs I read: https://developers.google.com/identity/protocols/oauth2/service-account https://cloud.google.com/storage/docs/uploading-objects#rest-upload-objects

Upvotes: 2

Views: 230

Answers (1)

rgd_dev
rgd_dev

Reputation: 53

I fixed the code based on the first comment, and now it's working like this:

import moment from 'moment';
import jsonwebtoken from 'jsonwebtoken';
import axios from 'axios';

export const authentication = function (): void {
    const nowInUnix = moment().unix();
    const secret = "-----BEGIN PRIVATE KEY-----YOUR_KEY-----END PRIVATE KEY-----\n";
    let claims = {
        "iss": "[email protected]",
        "scope": "https://www.googleapis.com/auth/devstorage.full_control",
        "aud": "https://oauth2.googleapis.com/token",
        "exp": nowInUnix + 3600,
        "iat": nowInUnix
    };
    const token = jsonwebtoken.sign(claims, secret, { algorithm: 'RS256'});
    const response: any = await axios.post(`https://oauth2.googleapis.com/token?grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion=${token}`)
        .catch(e => console.log('Error occured: \n' + e));
    console.log(response.data);
}

response:

{
  access_token: 'MY_TOKEN',
  expires_in: 3599,
  token_type: 'Bearer'
}

Upvotes: 3

Related Questions