Skip to content

Instantly share code, notes, and snippets.

@ryu1kn
Last active June 25, 2024 10:50
Show Gist options
  • Save ryu1kn/c76aed0af8728f659730d9c26c9ee0ed to your computer and use it in GitHub Desktop.
Save ryu1kn/c76aed0af8728f659730d9c26c9ee0ed to your computer and use it in GitHub Desktop.
Getting GCP access token from a service account key JSON file

Getting GCP access token from a service account key

Use your service account's key JSON file to get an access token to call Google APIs.

Good for seeing how things work, including the creation of JWT token.

To create a JWT token, you can replace create-jwt-token.sh script with tools like step.

If you just want to get an access token for a service account, you can do the same thing with just gcloud command. cf Authorization and authentication.

Prerequisites

  • Have a GCP project and a service account.
  • The service account has a permission for the request.
    • e.g. For listing buckets, "https://www.googleapis.com/auth/devstorage.read_only"
  • The service account's key JSON file is downloaded (here, key.json).
  • Commands available: jq, openssl

Usage

Get an access token.

$ ./get-access-token.sh /path/to/key.json "https://www.googleapis.com/auth/devstorage.read_only"
ya29...

You can call a Google API with the token. Here since we've requested storage readonly, we list buckets.

$ curl "https://www.googleapis.com/storage/v1/b?project=<your_project_id>" \
    -H "Authorization: Bearer ya29..."

References

#!/bin/bash
set -euo pipefail
base64var() {
printf "$1" | base64stream
}
base64stream() {
base64 | tr '/+' '_-' | tr -d '=\n'
}
key_json_file="$1"
scope="$2"
valid_for_sec="${3:-3600}"
private_key=$(jq -r .private_key $key_json_file)
sa_email=$(jq -r .client_email $key_json_file)
header='{"alg":"RS256","typ":"JWT"}'
claim=$(cat <<EOF | jq -c .
{
"iss": "$sa_email",
"scope": "$scope",
"aud": "https://www.googleapis.com/oauth2/v4/token",
"exp": $(($(date +%s) + $valid_for_sec)),
"iat": $(date +%s)
}
EOF
)
request_body="$(base64var "$header").$(base64var "$claim")"
signature=$(openssl dgst -sha256 -sign <(echo "$private_key") <(printf "$request_body") | base64stream)
printf "$request_body.$signature"
#!/bin/bash
set -euo pipefail
key_json_file="$1"
scope="$2"
jwt_token=$(./create-jwt-token.sh "$key_json_file" "$scope")
curl -s -X POST https://www.googleapis.com/oauth2/v4/token \
--data-urlencode 'grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer' \
--data-urlencode "assertion=$jwt_token" \
| jq -r .access_token
@jbauerrfid
Copy link

jbauerrfid commented Jun 25, 2024

Figured out how to do this in NodeJS:

const axios = require("axios");
const jwt = require('jsonwebtoken');

const credJson = /* TODO: put your credential JSON string here */;

const { client_email, private_key, private_key_id } = JSON.parse(credJson);

const currentDate = Math.floor(new Date().getTime() / 1000);

const url = "https://oauth2.googleapis.com/token";
const SCOPE = {
    "read-only": "https://www.googleapis.com/auth/devstorage.read_only",
    "read-write": "https://www.googleapis.com/auth/devstorage.read_write",
    "full-control": "https://www.googleapis.com/auth/devstorage.full_control",
    "cloud-platform.read-only": "https://www.googleapis.com/auth/cloud-platform.read-only",
    "cloud-platform": "https://www.googleapis.com/auth/cloud-platform"
};

const payload = {
    iss: client_email,
    scope: SCOPE["cloud-platform"],  // pick desired scope
    aud: url,
    exp: currentDate + 3600,
    iat: currentDate
};

const assertion = jwt.sign(payload, private_key, { algorithm: 'RS256', keyid: private_key_id });

const data = {
    grant_type: "urn:ietf:params:oauth:grant-type:jwt-bearer",
    assertion
};

axios.post(url, data, {headers: {'content-type': 'application/x-www-form-urlencoded'}})
    .then((response) => {
        console.log("SUCCESS, token: " + response.data.access_token);
        return response.data;
    })
    .catch((error) => {
        console.error(error)
        return undefined;
    });

so if someone already uses NodeJS, it should be easy to integrate.

Used the documentation from https://developers.google.com/identity/protocols/oauth2/service-account to create this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment