Reputation: 414
Per this documentation Addendum: Service account authorization without OAuth, it says
If the API you want to call has a service definition published in the Google APIs GitHub repository, you can make authorized API calls using a JWT instead of an access token
I see Google Cloud Storage published on that Github repository but I can not seem to be able to get a file on Google Cloud Storage with the approach in the documentation. According to JWT header and payload example show in step 3 of the documentation, I did the following adjustments
kid
from abcdef1234567890
to my service account private_key_id
iss
and sub
to my service account client_email
aud
to https://storage.googleapis.com/
iat
and exp
to now and now + 1 hourI use signed JWT as bearer token trying to get file from http://storage.googleapis.com/<bucket>/path/file
but I keep getting this response
<?xml version='1.0' encoding='UTF-8'?><Error><Code>AuthenticationRequired</Code><Message>Authentication required.</Message></Error>
Can we really use this approach with Google Cloud Storage? Am I doing anything wrong?
Note that I can access the file with oauth access_token when following another approach described on the same page documentation page but I prefer not to make a request to get access_token first before making a request to get the file.
Upvotes: 4
Views: 710
Reputation: 483
I drew the same conclusion as you from reading this documentation, but it doesn't work for me either on Google Cloud Storage.
It does work on some services like Google Cloud Pub/Sub.
I also confirmed that the Google Cloud SDK doesn't use the "Service account authorization without OAuth" method for GCS, but it does for Pub/Sub.
For example in the Node.js SDK, the variable determining whether or not to use this method is useSelfSignedJWT
in google-auth-library
:
const useSelfSignedJWT =
(!this.hasUserScopes() && url) ||
(this.useJWTAccessWithScope && this.hasAnyScopes());
A service like Pub/Sub that supports self-signed JWT sets useJWTAccessWithScope = true
, but GCS doesn't
set this variable.
That being said I forced the GCS SDK to use self-signed JWT and got it to work that way!
const { Storage } = require('@google-cloud/storage')
const storage = new Storage({
keyFilename: 'service-account-key.json'
})
storage.authClient.useJWTAccessWithScope = true
// Use client and watch how it doesn't call the OAuth2 endpoint,
// and requests are still successful.
The interesting thing to note is that the self-signed JWT that Google SDK generated is a bit different from what they document for Service account authorization without OAuth:
{
"iss": "[email protected]",
"sub": "[email protected]",
"scope": "https://www.googleapis.com/auth/iam https://www.googleapis.com/auth/cloud-platform https://www.googleapis.com/auth/devstorage.full_control",
"exp": 1234567890,
"iat": 1234567890
}
Whereas their documentation says to use a aud
field and doesn't mention scopes:
{ "iss": "[email protected]", "sub": "[email protected]", "aud": "https://firestore.googleapis.com/", "iat": 1511900000, "exp": 1511903600 }
So you can set a scope
field with a valid OAuth scope, e.g. for GCS. This did work for me on GCS, and it might work for other APIs that don't accept self-signed tokens with aud
.
Upvotes: 2