blob: 2240631e9af95f3c00649beb163769a823ef97f0 [file] [log] [blame]
C.J. Collier37141e42020-02-13 13:49:49 -08001# Copyright 2016 Google LLC
Jon Wayne Parrottab9eba32016-10-17 10:49:57 -07002#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15"""Service Accounts: JSON Web Token (JWT) Profile for OAuth 2.0
16
17This module implements the JWT Profile for OAuth 2.0 Authorization Grants
18as defined by `RFC 7523`_ with particular support for how this RFC is
19implemented in Google's infrastructure. Google refers to these credentials
20as *Service Accounts*.
21
22Service accounts are used for server-to-server communication, such as
23interactions between a web application server and a Google service. The
24service account belongs to your application instead of to an individual end
25user. In contrast to other OAuth 2.0 profiles, no users are involved and your
26application "acts" as the service account.
27
28Typically an application uses a service account when the application uses
29Google APIs to work with its own data rather than a user's data. For example,
30an application that uses Google Cloud Datastore for data persistence would use
31a service account to authenticate its calls to the Google Cloud Datastore API.
32However, an application that needs to access a user's Drive documents would
33use the normal OAuth 2.0 profile.
34
35Additionally, Google Apps domain administrators can grant service accounts
36`domain-wide delegation`_ authority to access user data on behalf of users in
37the domain.
38
39This profile uses a JWT to acquire an OAuth 2.0 access token. The JWT is used
40in place of the usual authorization token returned during the standard
41OAuth 2.0 Authorization Code grant. The JWT is only used for this purpose, as
42the acquired access token is used as the bearer token when making requests
43using these credentials.
44
45This profile differs from normal OAuth 2.0 profile because no user consent
46step is required. The use of the private key allows this profile to assert
47identity directly.
48
49This profile also differs from the :mod:`google.auth.jwt` authentication
50because the JWT credentials use the JWT directly as the bearer token. This
51profile instead only uses the JWT to obtain an OAuth 2.0 access token. The
52obtained OAuth 2.0 access token is used as the bearer token.
53
54Domain-wide delegation
55----------------------
56
57Domain-wide delegation allows a service account to access user data on
58behalf of any user in a Google Apps domain without consent from the user.
59For example, an application that uses the Google Calendar API to add events to
60the calendars of all users in a Google Apps domain would use a service account
61to access the Google Calendar API on behalf of users.
62
63The Google Apps administrator must explicitly authorize the service account to
64do this. This authorization step is referred to as "delegating domain-wide
65authority" to a service account.
66
67You can use domain-wise delegation by creating a set of credentials with a
68specific subject using :meth:`~Credentials.with_subject`.
69
70.. _RFC 7523: https://tools.ietf.org/html/rfc7523
71"""
72
Jon Wayne Parrott75c78b22017-03-23 13:14:53 -070073import copy
Jon Wayne Parrottab9eba32016-10-17 10:49:57 -070074import datetime
Jon Wayne Parrottab9eba32016-10-17 10:49:57 -070075
76from google.auth import _helpers
Jon Wayne Parrott807032c2016-10-18 09:38:26 -070077from google.auth import _service_account_info
Jon Wayne Parrottab9eba32016-10-17 10:49:57 -070078from google.auth import credentials
Jon Wayne Parrottab9eba32016-10-17 10:49:57 -070079from google.auth import jwt
80from google.oauth2 import _client
81
Albert-Jan Nijburgb7b48f12017-11-08 20:15:18 +000082_DEFAULT_TOKEN_LIFETIME_SECS = 3600 # 1 hour in seconds
Jon Wayne Parrottab9eba32016-10-17 10:49:57 -070083
84
Bu Sun Kim9eec0912019-10-21 17:04:21 -070085class Credentials(credentials.Signing, credentials.Scoped, credentials.Credentials):
Jon Wayne Parrottab9eba32016-10-17 10:49:57 -070086 """Service account credentials
87
88 Usually, you'll create these credentials with one of the helper
89 constructors. To create credentials using a Google service account
90 private key JSON file::
91
92 credentials = service_account.Credentials.from_service_account_file(
93 'service-account.json')
94
95 Or if you already have the service account file loaded::
96
97 service_account_info = json.load(open('service_account.json'))
98 credentials = service_account.Credentials.from_service_account_info(
99 service_account_info)
100
101 Both helper methods pass on arguments to the constructor, so you can
102 specify additional scopes and a subject if necessary::
103
104 credentials = service_account.Credentials.from_service_account_file(
105 'service-account.json',
106 scopes=['email'],
107 subject='user@example.com')
108
109 The credentials are considered immutable. If you want to modify the scopes
110 or the subject used for delegation, use :meth:`with_scopes` or
111 :meth:`with_subject`::
112
113 scoped_credentials = credentials.with_scopes(['email'])
114 delegated_credentials = credentials.with_subject(subject)
Bu Sun Kimb12488c2020-06-10 13:44:07 -0700115
116 To add a quota project, use :meth:`with_quota_project`::
117
118 credentials = credentials.with_quota_project('myproject-123')
Jon Wayne Parrottab9eba32016-10-17 10:49:57 -0700119 """
120
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700121 def __init__(
122 self,
123 signer,
124 service_account_email,
125 token_uri,
126 scopes=None,
127 subject=None,
128 project_id=None,
Bu Sun Kimb12488c2020-06-10 13:44:07 -0700129 quota_project_id=None,
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700130 additional_claims=None,
131 ):
Jon Wayne Parrottab9eba32016-10-17 10:49:57 -0700132 """
133 Args:
134 signer (google.auth.crypt.Signer): The signer used to sign JWTs.
135 service_account_email (str): The service account's email.
136 scopes (Sequence[str]): Scopes to request during the authorization
137 grant.
138 token_uri (str): The OAuth 2.0 Token URI.
139 subject (str): For domain-wide delegation, the email address of the
140 user to for which to request delegated access.
Hiranya Jayathilaka6a3f0ec2017-08-10 09:11:02 -0700141 project_id (str): Project ID associated with the service account
142 credential.
Bu Sun Kimb12488c2020-06-10 13:44:07 -0700143 quota_project_id (Optional[str]): The project ID used for quota and
144 billing.
Jon Wayne Parrottab9eba32016-10-17 10:49:57 -0700145 additional_claims (Mapping[str, str]): Any additional claims for
146 the JWT assertion used in the authorization grant.
147
148 .. note:: Typically one of the helper constructors
149 :meth:`from_service_account_file` or
150 :meth:`from_service_account_info` are used instead of calling the
151 constructor directly.
152 """
153 super(Credentials, self).__init__()
154
155 self._scopes = scopes
156 self._signer = signer
157 self._service_account_email = service_account_email
158 self._subject = subject
Hiranya Jayathilaka6a3f0ec2017-08-10 09:11:02 -0700159 self._project_id = project_id
Bu Sun Kimb12488c2020-06-10 13:44:07 -0700160 self._quota_project_id = quota_project_id
Jon Wayne Parrottab9eba32016-10-17 10:49:57 -0700161 self._token_uri = token_uri
162
163 if additional_claims is not None:
164 self._additional_claims = additional_claims
165 else:
166 self._additional_claims = {}
167
168 @classmethod
Jon Wayne Parrott807032c2016-10-18 09:38:26 -0700169 def _from_signer_and_info(cls, signer, info, **kwargs):
170 """Creates a Credentials instance from a signer and service account
171 info.
172
173 Args:
174 signer (google.auth.crypt.Signer): The signer used to sign JWTs.
175 info (Mapping[str, str]): The service account info.
176 kwargs: Additional arguments to pass to the constructor.
177
178 Returns:
179 google.auth.jwt.Credentials: The constructed credentials.
180
181 Raises:
182 ValueError: If the info is not in the expected format.
183 """
184 return cls(
185 signer,
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700186 service_account_email=info["client_email"],
187 token_uri=info["token_uri"],
188 project_id=info.get("project_id"),
189 **kwargs
190 )
Jon Wayne Parrott807032c2016-10-18 09:38:26 -0700191
192 @classmethod
Jon Wayne Parrottab9eba32016-10-17 10:49:57 -0700193 def from_service_account_info(cls, info, **kwargs):
194 """Creates a Credentials instance from parsed service account info.
195
196 Args:
197 info (Mapping[str, str]): The service account info in Google
198 format.
199 kwargs: Additional arguments to pass to the constructor.
200
201 Returns:
202 google.auth.service_account.Credentials: The constructed
203 credentials.
204
205 Raises:
206 ValueError: If the info is not in the expected format.
207 """
Jon Wayne Parrott807032c2016-10-18 09:38:26 -0700208 signer = _service_account_info.from_dict(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700209 info, require=["client_email", "token_uri"]
210 )
Jon Wayne Parrott807032c2016-10-18 09:38:26 -0700211 return cls._from_signer_and_info(signer, info, **kwargs)
Jon Wayne Parrottab9eba32016-10-17 10:49:57 -0700212
213 @classmethod
214 def from_service_account_file(cls, filename, **kwargs):
215 """Creates a Credentials instance from a service account json file.
216
217 Args:
218 filename (str): The path to the service account json file.
219 kwargs: Additional arguments to pass to the constructor.
220
221 Returns:
222 google.auth.service_account.Credentials: The constructed
223 credentials.
224 """
Jon Wayne Parrott807032c2016-10-18 09:38:26 -0700225 info, signer = _service_account_info.from_filename(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700226 filename, require=["client_email", "token_uri"]
227 )
Jon Wayne Parrott807032c2016-10-18 09:38:26 -0700228 return cls._from_signer_and_info(signer, info, **kwargs)
Jon Wayne Parrottab9eba32016-10-17 10:49:57 -0700229
Jon Wayne Parrottab9eba32016-10-17 10:49:57 -0700230 @property
Jon Wayne Parrott61ffb052016-11-08 09:30:30 -0800231 def service_account_email(self):
232 """The service account email."""
233 return self._service_account_email
234
235 @property
Hiranya Jayathilaka6a3f0ec2017-08-10 09:11:02 -0700236 def project_id(self):
237 """Project ID associated with this credential."""
238 return self._project_id
239
240 @property
Jon Wayne Parrottab9eba32016-10-17 10:49:57 -0700241 def requires_scopes(self):
242 """Checks if the credentials requires scopes.
243
244 Returns:
245 bool: True if there are no scopes set otherwise False.
246 """
247 return True if not self._scopes else False
248
249 @_helpers.copy_docstring(credentials.Scoped)
250 def with_scopes(self, scopes):
Christophe Tatonb649b432018-02-08 14:12:23 -0800251 return self.__class__(
Jon Wayne Parrottab9eba32016-10-17 10:49:57 -0700252 self._signer,
253 service_account_email=self._service_account_email,
254 scopes=scopes,
255 token_uri=self._token_uri,
256 subject=self._subject,
Hiranya Jayathilaka6a3f0ec2017-08-10 09:11:02 -0700257 project_id=self._project_id,
Bu Sun Kimb12488c2020-06-10 13:44:07 -0700258 quota_project_id=self._quota_project_id,
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700259 additional_claims=self._additional_claims.copy(),
260 )
Jon Wayne Parrottab9eba32016-10-17 10:49:57 -0700261
262 def with_subject(self, subject):
263 """Create a copy of these credentials with the specified subject.
264
265 Args:
266 subject (str): The subject claim.
267
268 Returns:
269 google.auth.service_account.Credentials: A new credentials
270 instance.
271 """
Christophe Tatonb649b432018-02-08 14:12:23 -0800272 return self.__class__(
Jon Wayne Parrottab9eba32016-10-17 10:49:57 -0700273 self._signer,
274 service_account_email=self._service_account_email,
275 scopes=self._scopes,
276 token_uri=self._token_uri,
277 subject=subject,
Hiranya Jayathilaka6a3f0ec2017-08-10 09:11:02 -0700278 project_id=self._project_id,
Bu Sun Kimb12488c2020-06-10 13:44:07 -0700279 quota_project_id=self._quota_project_id,
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700280 additional_claims=self._additional_claims.copy(),
281 )
Jon Wayne Parrottab9eba32016-10-17 10:49:57 -0700282
Jon Wayne Parrott75c78b22017-03-23 13:14:53 -0700283 def with_claims(self, additional_claims):
284 """Returns a copy of these credentials with modified claims.
285
286 Args:
287 additional_claims (Mapping[str, str]): Any additional claims for
288 the JWT payload. This will be merged with the current
289 additional claims.
290
291 Returns:
292 google.auth.service_account.Credentials: A new credentials
293 instance.
294 """
295 new_additional_claims = copy.deepcopy(self._additional_claims)
296 new_additional_claims.update(additional_claims or {})
297
Christophe Tatonb649b432018-02-08 14:12:23 -0800298 return self.__class__(
Jon Wayne Parrott75c78b22017-03-23 13:14:53 -0700299 self._signer,
300 service_account_email=self._service_account_email,
301 scopes=self._scopes,
302 token_uri=self._token_uri,
303 subject=self._subject,
Hiranya Jayathilaka6a3f0ec2017-08-10 09:11:02 -0700304 project_id=self._project_id,
Bu Sun Kimb12488c2020-06-10 13:44:07 -0700305 quota_project_id=self._quota_project_id,
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700306 additional_claims=new_additional_claims,
307 )
Jon Wayne Parrott75c78b22017-03-23 13:14:53 -0700308
Bu Sun Kim3dda7b22020-07-09 10:39:39 -0700309 @_helpers.copy_docstring(credentials.Credentials)
Bu Sun Kimb12488c2020-06-10 13:44:07 -0700310 def with_quota_project(self, quota_project_id):
Bu Sun Kimb12488c2020-06-10 13:44:07 -0700311
Bu Sun Kimb12488c2020-06-10 13:44:07 -0700312 return self.__class__(
313 self._signer,
314 service_account_email=self._service_account_email,
315 scopes=self._scopes,
316 token_uri=self._token_uri,
317 subject=self._subject,
318 project_id=self._project_id,
319 quota_project_id=quota_project_id,
320 additional_claims=self._additional_claims.copy(),
321 )
322
Jon Wayne Parrottab9eba32016-10-17 10:49:57 -0700323 def _make_authorization_grant_assertion(self):
324 """Create the OAuth 2.0 assertion.
325
326 This assertion is used during the OAuth 2.0 grant to acquire an
327 access token.
328
329 Returns:
330 bytes: The authorization grant assertion.
331 """
332 now = _helpers.utcnow()
333 lifetime = datetime.timedelta(seconds=_DEFAULT_TOKEN_LIFETIME_SECS)
334 expiry = now + lifetime
335
336 payload = {
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700337 "iat": _helpers.datetime_to_secs(now),
338 "exp": _helpers.datetime_to_secs(expiry),
Jon Wayne Parrottab9eba32016-10-17 10:49:57 -0700339 # The issuer must be the service account email.
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700340 "iss": self._service_account_email,
Jon Wayne Parrottab9eba32016-10-17 10:49:57 -0700341 # The audience must be the auth token endpoint's URI
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700342 "aud": self._token_uri,
343 "scope": _helpers.scopes_to_string(self._scopes or ()),
Jon Wayne Parrottab9eba32016-10-17 10:49:57 -0700344 }
345
346 payload.update(self._additional_claims)
347
348 # The subject can be a user email for domain-wide delegation.
349 if self._subject:
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700350 payload.setdefault("sub", self._subject)
Jon Wayne Parrottab9eba32016-10-17 10:49:57 -0700351
352 token = jwt.encode(self._signer, payload)
353
354 return token
355
356 @_helpers.copy_docstring(credentials.Credentials)
357 def refresh(self, request):
358 assertion = self._make_authorization_grant_assertion()
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700359 access_token, expiry, _ = _client.jwt_grant(request, self._token_uri, assertion)
Jon Wayne Parrottab9eba32016-10-17 10:49:57 -0700360 self.token = access_token
361 self.expiry = expiry
362
363 @_helpers.copy_docstring(credentials.Signing)
364 def sign_bytes(self, message):
365 return self._signer.sign(message)
Jon Wayne Parrott4c883f02016-12-02 14:26:33 -0800366
367 @property
368 @_helpers.copy_docstring(credentials.Signing)
Jon Wayne Parrottd7221672017-02-16 09:05:11 -0800369 def signer(self):
370 return self._signer
371
372 @property
373 @_helpers.copy_docstring(credentials.Signing)
Jon Wayne Parrott4c883f02016-12-02 14:26:33 -0800374 def signer_email(self):
375 return self._service_account_email
Christophe Tatonb649b432018-02-08 14:12:23 -0800376
377
378class IDTokenCredentials(credentials.Signing, credentials.Credentials):
379 """Open ID Connect ID Token-based service account credentials.
380
381 These credentials are largely similar to :class:`.Credentials`, but instead
382 of using an OAuth 2.0 Access Token as the bearer token, they use an Open
383 ID Connect ID Token as the bearer token. These credentials are useful when
384 communicating to services that require ID Tokens and can not accept access
385 tokens.
386
387 Usually, you'll create these credentials with one of the helper
388 constructors. To create credentials using a Google service account
389 private key JSON file::
390
391 credentials = (
392 service_account.IDTokenCredentials.from_service_account_file(
393 'service-account.json'))
394
395 Or if you already have the service account file loaded::
396
397 service_account_info = json.load(open('service_account.json'))
398 credentials = (
399 service_account.IDTokenCredentials.from_service_account_info(
400 service_account_info))
401
402 Both helper methods pass on arguments to the constructor, so you can
403 specify additional scopes and a subject if necessary::
404
405 credentials = (
406 service_account.IDTokenCredentials.from_service_account_file(
407 'service-account.json',
408 scopes=['email'],
409 subject='user@example.com'))
410`
411 The credentials are considered immutable. If you want to modify the scopes
412 or the subject used for delegation, use :meth:`with_scopes` or
413 :meth:`with_subject`::
414
415 scoped_credentials = credentials.with_scopes(['email'])
416 delegated_credentials = credentials.with_subject(subject)
417
418 """
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700419
420 def __init__(
421 self,
422 signer,
423 service_account_email,
424 token_uri,
425 target_audience,
426 additional_claims=None,
Bu Sun Kim3dda7b22020-07-09 10:39:39 -0700427 quota_project_id=None,
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700428 ):
Christophe Tatonb649b432018-02-08 14:12:23 -0800429 """
430 Args:
431 signer (google.auth.crypt.Signer): The signer used to sign JWTs.
432 service_account_email (str): The service account's email.
433 token_uri (str): The OAuth 2.0 Token URI.
434 target_audience (str): The intended audience for these credentials,
435 used when requesting the ID Token. The ID Token's ``aud`` claim
436 will be set to this string.
437 additional_claims (Mapping[str, str]): Any additional claims for
438 the JWT assertion used in the authorization grant.
Bu Sun Kim3dda7b22020-07-09 10:39:39 -0700439 quota_project_id (Optional[str]): The project ID used for quota and billing.
Christophe Tatonb649b432018-02-08 14:12:23 -0800440 .. note:: Typically one of the helper constructors
441 :meth:`from_service_account_file` or
442 :meth:`from_service_account_info` are used instead of calling the
443 constructor directly.
444 """
445 super(IDTokenCredentials, self).__init__()
446 self._signer = signer
447 self._service_account_email = service_account_email
448 self._token_uri = token_uri
449 self._target_audience = target_audience
Bu Sun Kim3dda7b22020-07-09 10:39:39 -0700450 self._quota_project_id = quota_project_id
Christophe Tatonb649b432018-02-08 14:12:23 -0800451
452 if additional_claims is not None:
453 self._additional_claims = additional_claims
454 else:
455 self._additional_claims = {}
456
457 @classmethod
458 def _from_signer_and_info(cls, signer, info, **kwargs):
459 """Creates a credentials instance from a signer and service account
460 info.
461
462 Args:
463 signer (google.auth.crypt.Signer): The signer used to sign JWTs.
464 info (Mapping[str, str]): The service account info.
465 kwargs: Additional arguments to pass to the constructor.
466
467 Returns:
468 google.auth.jwt.IDTokenCredentials: The constructed credentials.
469
470 Raises:
471 ValueError: If the info is not in the expected format.
472 """
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700473 kwargs.setdefault("service_account_email", info["client_email"])
474 kwargs.setdefault("token_uri", info["token_uri"])
Christophe Tatonb649b432018-02-08 14:12:23 -0800475 return cls(signer, **kwargs)
476
477 @classmethod
478 def from_service_account_info(cls, info, **kwargs):
479 """Creates a credentials instance from parsed service account info.
480
481 Args:
482 info (Mapping[str, str]): The service account info in Google
483 format.
484 kwargs: Additional arguments to pass to the constructor.
485
486 Returns:
487 google.auth.service_account.IDTokenCredentials: The constructed
488 credentials.
489
490 Raises:
491 ValueError: If the info is not in the expected format.
492 """
493 signer = _service_account_info.from_dict(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700494 info, require=["client_email", "token_uri"]
495 )
Christophe Tatonb649b432018-02-08 14:12:23 -0800496 return cls._from_signer_and_info(signer, info, **kwargs)
497
498 @classmethod
499 def from_service_account_file(cls, filename, **kwargs):
500 """Creates a credentials instance from a service account json file.
501
502 Args:
503 filename (str): The path to the service account json file.
504 kwargs: Additional arguments to pass to the constructor.
505
506 Returns:
507 google.auth.service_account.IDTokenCredentials: The constructed
508 credentials.
509 """
510 info, signer = _service_account_info.from_filename(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700511 filename, require=["client_email", "token_uri"]
512 )
Christophe Tatonb649b432018-02-08 14:12:23 -0800513 return cls._from_signer_and_info(signer, info, **kwargs)
514
515 def with_target_audience(self, target_audience):
516 """Create a copy of these credentials with the specified target
517 audience.
518
519 Args:
520 target_audience (str): The intended audience for these credentials,
521 used when requesting the ID Token.
522
523 Returns:
524 google.auth.service_account.IDTokenCredentials: A new credentials
525 instance.
526 """
527 return self.__class__(
528 self._signer,
529 service_account_email=self._service_account_email,
530 token_uri=self._token_uri,
531 target_audience=target_audience,
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700532 additional_claims=self._additional_claims.copy(),
Bu Sun Kim3dda7b22020-07-09 10:39:39 -0700533 quota_project_id=self.quota_project_id,
534 )
535
536 @_helpers.copy_docstring(credentials.Credentials)
537 def with_quota_project(self, quota_project_id):
538 return self.__class__(
539 self._signer,
540 service_account_email=self._service_account_email,
541 token_uri=self._token_uri,
542 target_audience=self._target_audience,
543 additional_claims=self._additional_claims.copy(),
544 quota_project_id=quota_project_id,
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700545 )
Christophe Tatonb649b432018-02-08 14:12:23 -0800546
547 def _make_authorization_grant_assertion(self):
548 """Create the OAuth 2.0 assertion.
549
550 This assertion is used during the OAuth 2.0 grant to acquire an
551 ID token.
552
553 Returns:
554 bytes: The authorization grant assertion.
555 """
556 now = _helpers.utcnow()
557 lifetime = datetime.timedelta(seconds=_DEFAULT_TOKEN_LIFETIME_SECS)
558 expiry = now + lifetime
559
560 payload = {
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700561 "iat": _helpers.datetime_to_secs(now),
562 "exp": _helpers.datetime_to_secs(expiry),
Christophe Tatonb649b432018-02-08 14:12:23 -0800563 # The issuer must be the service account email.
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700564 "iss": self.service_account_email,
Christophe Tatonb649b432018-02-08 14:12:23 -0800565 # The audience must be the auth token endpoint's URI
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700566 "aud": self._token_uri,
Christophe Tatonb649b432018-02-08 14:12:23 -0800567 # The target audience specifies which service the ID token is
568 # intended for.
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700569 "target_audience": self._target_audience,
Christophe Tatonb649b432018-02-08 14:12:23 -0800570 }
571
572 payload.update(self._additional_claims)
573
574 token = jwt.encode(self._signer, payload)
575
576 return token
577
578 @_helpers.copy_docstring(credentials.Credentials)
579 def refresh(self, request):
580 assertion = self._make_authorization_grant_assertion()
581 access_token, expiry, _ = _client.id_token_jwt_grant(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700582 request, self._token_uri, assertion
583 )
Christophe Tatonb649b432018-02-08 14:12:23 -0800584 self.token = access_token
585 self.expiry = expiry
586
587 @property
588 def service_account_email(self):
589 """The service account email."""
590 return self._service_account_email
591
592 @_helpers.copy_docstring(credentials.Signing)
593 def sign_bytes(self, message):
594 return self._signer.sign(message)
595
596 @property
597 @_helpers.copy_docstring(credentials.Signing)
598 def signer(self):
599 return self._signer
600
601 @property
602 @_helpers.copy_docstring(credentials.Signing)
603 def signer_email(self):
604 return self._service_account_email