1

In pub sub rest API how to get the access token with service account role of publisher to make the rest api calls ?

What is the minimum permission/role required to get the access token ?

I am using node.js programming language but don't want to use any node module just want the rest API approach.

Nazim
  • 564
  • 5
  • 13

2 Answers2

2

If you don’t yet have a service account key, you can create one by following the instructions here: https://cloud.google.com/iam/docs/creating-managing-service-account-keys#creating_service_account_keys

The role in your case should be Pub/Sub > Pub/Sub Publisher. If you’re just doing some local scripting and need a token to pass into your requests, you can pass credentials for this service account by setting the environment variable GOOGLE_APPLICATION_CREDENTIALS to the path to your JSON key file. (Instructions)

Then, you could add --header "Authorization: Bearer $(gcloud auth print-access-token)" to your HTTP/REST API request.

--

However, if you’re building a web application or something that will need to programmatically get tokens, you’ll want to use OAuth. The documentation is here: https://developers.google.com/identity/protocols/oauth2/service-account#httprest

Once you’ve got your service account and key, you use the service account’s credentials to request an access token from the OAuth2.0 auth server. (Instructions) The narrowest scope you can request is https://www.googleapis.com/auth/pubsub. While you can do this without any client libraries strictly for HTTP/REST as shown in the instructions, Google strongly encourages you to use a library, such as the Google API client libraries.

Then, your application can use the access token to call the Pub/Sub REST API, by including it in the Authorization: Bearer header.

For more context on service account tokens, you might be interested in this answer: https://stackoverflow.com/a/53472880/14018476

1

Stitching together instructions from 3 places to make an end to end guide. I'm sharing code snippets in Python3, but you can adapt the same to your coding language.

A. Base64 encode your message/payload

Covering this early instead of at last. Sample payload: {"message": "Hello world 1"}
Ensure it's "stringified". Convert it to a base64 string. This site is useful: https://www.base64encode.org/
Doing this in python:

import json, base64
payload = {"message": "Hello World 1"}
data = base64.b64encode(bytes(json.dumps(payload), 'utf-8')).decode("utf-8")
print(data)

eyJtZXNzYWdlIjogIkhlbGxvIFdvcmxkIDEifQ==

This will be used in section C.

Reference to this in docs along with other noise: https://cloud.google.com/pubsub/docs/reference/rest/v1/PubsubMessage

B. Create a JWT token out of your service account key

Following the section "Addendum: Service account authorization without OAuth" here: https://developers.google.com/identity/protocols/oauth2/service-account#jwt-auth
Got your service account key? You can directly create a JWT from it, in-house. No external oauth providers etc to bother with.

Python code copied from the above link and adapted to make it more sensible.

For simplicity sake, consider the key file is saved in "serviceackey.json" in same folder as this program.

# pip install pyjwt
import time, jwt, json

sa = json.load(open("serviceackey.json","r"))

iat = time.time()
exp = iat + 3600
payload = {
    "iss": sa["client_email"],
    "sub": sa["client_email"],
    "aud": "https://pubsub.googleapis.com/",
    "iat": iat,
    "exp": exp
}
additional_headers = { "kid": sa["private_key_id"] }

signed_jwt = jwt.encode(payload, sa["private_key"], 
    headers=additional_headers, algorithm="RS256")
print(signed_jwt)

Output: You'll get a 700-odd char long string that is your JWToken. You can run it by jwt.io and you'll see it's got all the stuff described above loaded in it. This token is valid for an hour. (I haven't tested what happens if I increase the exp above to more than an hour)

C. Make the API call to google's pubsub url

Pub/sub publishing api call described here:
https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.topics/publish

POST api call to url: https://pubsub.googleapis.com/v1/{topic}:publish

Replace {topic} with your topic's full name as seen in gray in your Pub/Sub Topics listing (click to copy to clipboard), it will have your project id also inside it. It looks like:
projects/<PROJECT ID>/topics/<TOPIC>

The request body has to be like:

{
  "messages": [
    { "data": "<Base64 text>" }
  ]
}

<Base64 text> is what you created in section A out of your payload.

You can include multiple payloads in the same api call by adding to the messages array above.

Add the JWT created in section B as a header in this API call:
Authorization: Bearer <JWT>

Set this up in Postman and give it a shot! Success response should look like:

Run the api call. Successful response will contain message ids, like:
{
    "messageIds": [
        "2821450199040130",
        "2821450199040131"
    ]
}

Note: That JWT token expires in an hour. Go make a new one if you took a break in the middle.

Nikhil VJ
  • 5,630
  • 7
  • 34
  • 55