Get FCM Service Account Access Token in Ruby
by mmyoji
2 min read
When you want to send a push notification through
Firebase Cloud Messaging
(FCM), you have to get access token
for it.
As
this page
says, you need a service account JSON file from your Firebase project
and can
get the access token with this JSON file and Google's Ruby SDK.
However, Google's Ruby SDKs are always confusing and not well-documented.
If you have a trouble to use it, this post will help you.
Get Access Token with Ruby SDK
Suppose you already have the Service Account JSON file.
If you already use google-api-client gem, you don't need to install extra dependencies to your project.
If you don't, use
googleauth gem for the
porpose. ( google-api-client
depends on the googleauth
)
For the Service Account, use the following code like README.md says:
I refers googleauth
v0.7.1 here.
require "googleauth"
# scope for FCM
scope = "https://www.googleapis.com/auth/firebase.messaging"
authorizer = Google::Auth::ServiceAccountCredentials.make_creds(
json_key_io: File.open('/path/to/service_account_json_key.json'),
scope: scope,
)
authorizer.fetch_access_token!
# You can access the token with this method.
authorizer.access_token
# You can know the expiration time with this method.
authorizer.expires_at
And if you want to cache the token, you can use 2 Stores classes.
Google::Auth::Stores::FileTokenStore
Google::Auth::Stores::RedisTokenStore
You will use the latter Redis store in most cases because the File one isn't
thread-safe (if
this code
is YAML::Store.new(path, true)
, it's thread-safe.),
The usage is like that:
require "googleauth"
require "googleauth/stores/redis_token_store"
ACCESS_TOKEN = "access_token"
EXPIRES_AT = "expires_at"
# this is from https://github.com/redis/redis-rb
redis = Redis.new(url: "redis://:p4ssw0rd@10.0.1.1:6380/15")
store = Google::Auth::Stores::RedisTokenStore.new(redis: redis)
authorizer = Google::Auth::ServiceAccountCredentials.make_creds(options)
if store.load(ACCESS_TOKEN) && store.load(EXPIRES_AT)
authorizer.access_token = store.load(ACCESS_TOKEN)
# this `#expires_at=` method convert Integer to Time.
authorizer.expires_at = store.load(EXPIRES_AT)
end
# this `#expired?` method will returns false if `#expires_at` is not set. confusing.
if authorizer.access_token.nil? || (authorizer.expires_at && authorizer.expired?)
authorizer.fetch_access_token!
store.store(ACCESS_TOKEN, authorizer.access_token)
store.store(EXPIRES_AT, authorizer.expires_at.to_i)
end
# you can almost always valid access token.
authorizer.access_token
Or your app process lives for a long time, you just use singleton class for it.