blob: c4898a247ba42d812a45bb5f21f3319f692d9714 [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 Kim41599ae2020-09-02 12:55:42 -060085class Credentials(
86 credentials.Signing, credentials.Scoped, credentials.CredentialsWithQuotaProject
87):
Jon Wayne Parrottab9eba32016-10-17 10:49:57 -070088 """Service account credentials
89
90 Usually, you'll create these credentials with one of the helper
91 constructors. To create credentials using a Google service account
92 private key JSON file::
93
94 credentials = service_account.Credentials.from_service_account_file(
95 'service-account.json')
96
97 Or if you already have the service account file loaded::
98
99 service_account_info = json.load(open('service_account.json'))
100 credentials = service_account.Credentials.from_service_account_info(
101 service_account_info)
102
103 Both helper methods pass on arguments to the constructor, so you can
104 specify additional scopes and a subject if necessary::
105
106 credentials = service_account.Credentials.from_service_account_file(
107 'service-account.json',
108 scopes=['email'],
109 subject='user@example.com')
110
111 The credentials are considered immutable. If you want to modify the scopes
112 or the subject used for delegation, use :meth:`with_scopes` or
113 :meth:`with_subject`::
114
115 scoped_credentials = credentials.with_scopes(['email'])
116 delegated_credentials = credentials.with_subject(subject)
Bu Sun Kimb12488c2020-06-10 13:44:07 -0700117
118 To add a quota project, use :meth:`with_quota_project`::
119
120 credentials = credentials.with_quota_project('myproject-123')
Jon Wayne Parrottab9eba32016-10-17 10:49:57 -0700121 """
122
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700123 def __init__(
124 self,
125 signer,
126 service_account_email,
127 token_uri,
128 scopes=None,
129 subject=None,
130 project_id=None,
Bu Sun Kimb12488c2020-06-10 13:44:07 -0700131 quota_project_id=None,
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700132 additional_claims=None,
133 ):
Jon Wayne Parrottab9eba32016-10-17 10:49:57 -0700134 """
135 Args:
136 signer (google.auth.crypt.Signer): The signer used to sign JWTs.
137 service_account_email (str): The service account's email.
138 scopes (Sequence[str]): Scopes to request during the authorization
139 grant.
140 token_uri (str): The OAuth 2.0 Token URI.
141 subject (str): For domain-wide delegation, the email address of the
142 user to for which to request delegated access.
Hiranya Jayathilaka6a3f0ec2017-08-10 09:11:02 -0700143 project_id (str): Project ID associated with the service account
144 credential.
Bu Sun Kimb12488c2020-06-10 13:44:07 -0700145 quota_project_id (Optional[str]): The project ID used for quota and
146 billing.
Jon Wayne Parrottab9eba32016-10-17 10:49:57 -0700147 additional_claims (Mapping[str, str]): Any additional claims for
148 the JWT assertion used in the authorization grant.
149
150 .. note:: Typically one of the helper constructors
151 :meth:`from_service_account_file` or
152 :meth:`from_service_account_info` are used instead of calling the
153 constructor directly.
154 """
155 super(Credentials, self).__init__()
156
157 self._scopes = scopes
158 self._signer = signer
159 self._service_account_email = service_account_email
160 self._subject = subject
Hiranya Jayathilaka6a3f0ec2017-08-10 09:11:02 -0700161 self._project_id = project_id
Bu Sun Kimb12488c2020-06-10 13:44:07 -0700162 self._quota_project_id = quota_project_id
Jon Wayne Parrottab9eba32016-10-17 10:49:57 -0700163 self._token_uri = token_uri
164
165 if additional_claims is not None:
166 self._additional_claims = additional_claims
167 else:
168 self._additional_claims = {}
169
170 @classmethod
Jon Wayne Parrott807032c2016-10-18 09:38:26 -0700171 def _from_signer_and_info(cls, signer, info, **kwargs):
172 """Creates a Credentials instance from a signer and service account
173 info.
174
175 Args:
176 signer (google.auth.crypt.Signer): The signer used to sign JWTs.
177 info (Mapping[str, str]): The service account info.
178 kwargs: Additional arguments to pass to the constructor.
179
180 Returns:
181 google.auth.jwt.Credentials: The constructed credentials.
182
183 Raises:
184 ValueError: If the info is not in the expected format.
185 """
186 return cls(
187 signer,
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700188 service_account_email=info["client_email"],
189 token_uri=info["token_uri"],
190 project_id=info.get("project_id"),
191 **kwargs
192 )
Jon Wayne Parrott807032c2016-10-18 09:38:26 -0700193
194 @classmethod
Jon Wayne Parrottab9eba32016-10-17 10:49:57 -0700195 def from_service_account_info(cls, info, **kwargs):
196 """Creates a Credentials instance from parsed service account info.
197
198 Args:
199 info (Mapping[str, str]): The service account info in Google
200 format.
201 kwargs: Additional arguments to pass to the constructor.
202
203 Returns:
204 google.auth.service_account.Credentials: The constructed
205 credentials.
206
207 Raises:
208 ValueError: If the info is not in the expected format.
209 """
Jon Wayne Parrott807032c2016-10-18 09:38:26 -0700210 signer = _service_account_info.from_dict(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700211 info, require=["client_email", "token_uri"]
212 )
Jon Wayne Parrott807032c2016-10-18 09:38:26 -0700213 return cls._from_signer_and_info(signer, info, **kwargs)
Jon Wayne Parrottab9eba32016-10-17 10:49:57 -0700214
215 @classmethod
216 def from_service_account_file(cls, filename, **kwargs):
217 """Creates a Credentials instance from a service account json file.
218
219 Args:
220 filename (str): The path to the service account json file.
221 kwargs: Additional arguments to pass to the constructor.
222
223 Returns:
224 google.auth.service_account.Credentials: The constructed
225 credentials.
226 """
Jon Wayne Parrott807032c2016-10-18 09:38:26 -0700227 info, signer = _service_account_info.from_filename(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700228 filename, require=["client_email", "token_uri"]
229 )
Jon Wayne Parrott807032c2016-10-18 09:38:26 -0700230 return cls._from_signer_and_info(signer, info, **kwargs)
Jon Wayne Parrottab9eba32016-10-17 10:49:57 -0700231
Jon Wayne Parrottab9eba32016-10-17 10:49:57 -0700232 @property
Jon Wayne Parrott61ffb052016-11-08 09:30:30 -0800233 def service_account_email(self):
234 """The service account email."""
235 return self._service_account_email
236
237 @property
Hiranya Jayathilaka6a3f0ec2017-08-10 09:11:02 -0700238 def project_id(self):
239 """Project ID associated with this credential."""
240 return self._project_id
241
242 @property
Jon Wayne Parrottab9eba32016-10-17 10:49:57 -0700243 def requires_scopes(self):
244 """Checks if the credentials requires scopes.
245
246 Returns:
247 bool: True if there are no scopes set otherwise False.
248 """
249 return True if not self._scopes else False
250
251 @_helpers.copy_docstring(credentials.Scoped)
252 def with_scopes(self, scopes):
Christophe Tatonb649b432018-02-08 14:12:23 -0800253 return self.__class__(
Jon Wayne Parrottab9eba32016-10-17 10:49:57 -0700254 self._signer,
255 service_account_email=self._service_account_email,
256 scopes=scopes,
257 token_uri=self._token_uri,
258 subject=self._subject,
Hiranya Jayathilaka6a3f0ec2017-08-10 09:11:02 -0700259 project_id=self._project_id,
Bu Sun Kimb12488c2020-06-10 13:44:07 -0700260 quota_project_id=self._quota_project_id,
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700261 additional_claims=self._additional_claims.copy(),
262 )
Jon Wayne Parrottab9eba32016-10-17 10:49:57 -0700263
264 def with_subject(self, subject):
265 """Create a copy of these credentials with the specified subject.
266
267 Args:
268 subject (str): The subject claim.
269
270 Returns:
271 google.auth.service_account.Credentials: A new credentials
272 instance.
273 """
Christophe Tatonb649b432018-02-08 14:12:23 -0800274 return self.__class__(
Jon Wayne Parrottab9eba32016-10-17 10:49:57 -0700275 self._signer,
276 service_account_email=self._service_account_email,
277 scopes=self._scopes,
278 token_uri=self._token_uri,
279 subject=subject,
Hiranya Jayathilaka6a3f0ec2017-08-10 09:11:02 -0700280 project_id=self._project_id,
Bu Sun Kimb12488c2020-06-10 13:44:07 -0700281 quota_project_id=self._quota_project_id,
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700282 additional_claims=self._additional_claims.copy(),
283 )
Jon Wayne Parrottab9eba32016-10-17 10:49:57 -0700284
Jon Wayne Parrott75c78b22017-03-23 13:14:53 -0700285 def with_claims(self, additional_claims):
286 """Returns a copy of these credentials with modified claims.
287
288 Args:
289 additional_claims (Mapping[str, str]): Any additional claims for
290 the JWT payload. This will be merged with the current
291 additional claims.
292
293 Returns:
294 google.auth.service_account.Credentials: A new credentials
295 instance.
296 """
297 new_additional_claims = copy.deepcopy(self._additional_claims)
298 new_additional_claims.update(additional_claims or {})
299
Christophe Tatonb649b432018-02-08 14:12:23 -0800300 return self.__class__(
Jon Wayne Parrott75c78b22017-03-23 13:14:53 -0700301 self._signer,
302 service_account_email=self._service_account_email,
303 scopes=self._scopes,
304 token_uri=self._token_uri,
305 subject=self._subject,
Hiranya Jayathilaka6a3f0ec2017-08-10 09:11:02 -0700306 project_id=self._project_id,
Bu Sun Kimb12488c2020-06-10 13:44:07 -0700307 quota_project_id=self._quota_project_id,
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700308 additional_claims=new_additional_claims,
309 )
Jon Wayne Parrott75c78b22017-03-23 13:14:53 -0700310
Bu Sun Kim41599ae2020-09-02 12:55:42 -0600311 @_helpers.copy_docstring(credentials.CredentialsWithQuotaProject)
Bu Sun Kimb12488c2020-06-10 13:44:07 -0700312 def with_quota_project(self, quota_project_id):
Bu Sun Kimb12488c2020-06-10 13:44:07 -0700313
Bu Sun Kimb12488c2020-06-10 13:44:07 -0700314 return self.__class__(
315 self._signer,
316 service_account_email=self._service_account_email,
317 scopes=self._scopes,
318 token_uri=self._token_uri,
319 subject=self._subject,
320 project_id=self._project_id,
321 quota_project_id=quota_project_id,
322 additional_claims=self._additional_claims.copy(),
323 )
324
Jon Wayne Parrottab9eba32016-10-17 10:49:57 -0700325 def _make_authorization_grant_assertion(self):
326 """Create the OAuth 2.0 assertion.
327
328 This assertion is used during the OAuth 2.0 grant to acquire an
329 access token.
330
331 Returns:
332 bytes: The authorization grant assertion.
333 """
334 now = _helpers.utcnow()
335 lifetime = datetime.timedelta(seconds=_DEFAULT_TOKEN_LIFETIME_SECS)
336 expiry = now + lifetime
337
338 payload = {
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700339 "iat": _helpers.datetime_to_secs(now),
340 "exp": _helpers.datetime_to_secs(expiry),
Jon Wayne Parrottab9eba32016-10-17 10:49:57 -0700341 # The issuer must be the service account email.
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700342 "iss": self._service_account_email,
Jon Wayne Parrottab9eba32016-10-17 10:49:57 -0700343 # The audience must be the auth token endpoint's URI
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700344 "aud": self._token_uri,
345 "scope": _helpers.scopes_to_string(self._scopes or ()),
Jon Wayne Parrottab9eba32016-10-17 10:49:57 -0700346 }
347
348 payload.update(self._additional_claims)
349
350 # The subject can be a user email for domain-wide delegation.
351 if self._subject:
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700352 payload.setdefault("sub", self._subject)
Jon Wayne Parrottab9eba32016-10-17 10:49:57 -0700353
354 token = jwt.encode(self._signer, payload)
355
356 return token
357
358 @_helpers.copy_docstring(credentials.Credentials)
359 def refresh(self, request):
360 assertion = self._make_authorization_grant_assertion()
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700361 access_token, expiry, _ = _client.jwt_grant(request, self._token_uri, assertion)
Jon Wayne Parrottab9eba32016-10-17 10:49:57 -0700362 self.token = access_token
363 self.expiry = expiry
364
365 @_helpers.copy_docstring(credentials.Signing)
366 def sign_bytes(self, message):
367 return self._signer.sign(message)
Jon Wayne Parrott4c883f02016-12-02 14:26:33 -0800368
369 @property
370 @_helpers.copy_docstring(credentials.Signing)
Jon Wayne Parrottd7221672017-02-16 09:05:11 -0800371 def signer(self):
372 return self._signer
373
374 @property
375 @_helpers.copy_docstring(credentials.Signing)
Jon Wayne Parrott4c883f02016-12-02 14:26:33 -0800376 def signer_email(self):
377 return self._service_account_email
Christophe Tatonb649b432018-02-08 14:12:23 -0800378
379
Bu Sun Kim41599ae2020-09-02 12:55:42 -0600380class IDTokenCredentials(credentials.Signing, credentials.CredentialsWithQuotaProject):
Christophe Tatonb649b432018-02-08 14:12:23 -0800381 """Open ID Connect ID Token-based service account credentials.
382
383 These credentials are largely similar to :class:`.Credentials`, but instead
384 of using an OAuth 2.0 Access Token as the bearer token, they use an Open
385 ID Connect ID Token as the bearer token. These credentials are useful when
386 communicating to services that require ID Tokens and can not accept access
387 tokens.
388
389 Usually, you'll create these credentials with one of the helper
390 constructors. To create credentials using a Google service account
391 private key JSON file::
392
393 credentials = (
394 service_account.IDTokenCredentials.from_service_account_file(
395 'service-account.json'))
396
397 Or if you already have the service account file loaded::
398
399 service_account_info = json.load(open('service_account.json'))
400 credentials = (
401 service_account.IDTokenCredentials.from_service_account_info(
402 service_account_info))
403
404 Both helper methods pass on arguments to the constructor, so you can
405 specify additional scopes and a subject if necessary::
406
407 credentials = (
408 service_account.IDTokenCredentials.from_service_account_file(
409 'service-account.json',
410 scopes=['email'],
411 subject='user@example.com'))
412`
413 The credentials are considered immutable. If you want to modify the scopes
414 or the subject used for delegation, use :meth:`with_scopes` or
415 :meth:`with_subject`::
416
417 scoped_credentials = credentials.with_scopes(['email'])
418 delegated_credentials = credentials.with_subject(subject)
419
420 """
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700421
422 def __init__(
423 self,
424 signer,
425 service_account_email,
426 token_uri,
427 target_audience,
428 additional_claims=None,
Bu Sun Kim3dda7b22020-07-09 10:39:39 -0700429 quota_project_id=None,
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700430 ):
Christophe Tatonb649b432018-02-08 14:12:23 -0800431 """
432 Args:
433 signer (google.auth.crypt.Signer): The signer used to sign JWTs.
434 service_account_email (str): The service account's email.
435 token_uri (str): The OAuth 2.0 Token URI.
436 target_audience (str): The intended audience for these credentials,
437 used when requesting the ID Token. The ID Token's ``aud`` claim
438 will be set to this string.
439 additional_claims (Mapping[str, str]): Any additional claims for
440 the JWT assertion used in the authorization grant.
Bu Sun Kim3dda7b22020-07-09 10:39:39 -0700441 quota_project_id (Optional[str]): The project ID used for quota and billing.
Christophe Tatonb649b432018-02-08 14:12:23 -0800442 .. note:: Typically one of the helper constructors
443 :meth:`from_service_account_file` or
444 :meth:`from_service_account_info` are used instead of calling the
445 constructor directly.
446 """
447 super(IDTokenCredentials, self).__init__()
448 self._signer = signer
449 self._service_account_email = service_account_email
450 self._token_uri = token_uri
451 self._target_audience = target_audience
Bu Sun Kim3dda7b22020-07-09 10:39:39 -0700452 self._quota_project_id = quota_project_id
Christophe Tatonb649b432018-02-08 14:12:23 -0800453
454 if additional_claims is not None:
455 self._additional_claims = additional_claims
456 else:
457 self._additional_claims = {}
458
459 @classmethod
460 def _from_signer_and_info(cls, signer, info, **kwargs):
461 """Creates a credentials instance from a signer and service account
462 info.
463
464 Args:
465 signer (google.auth.crypt.Signer): The signer used to sign JWTs.
466 info (Mapping[str, str]): The service account info.
467 kwargs: Additional arguments to pass to the constructor.
468
469 Returns:
470 google.auth.jwt.IDTokenCredentials: The constructed credentials.
471
472 Raises:
473 ValueError: If the info is not in the expected format.
474 """
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700475 kwargs.setdefault("service_account_email", info["client_email"])
476 kwargs.setdefault("token_uri", info["token_uri"])
Christophe Tatonb649b432018-02-08 14:12:23 -0800477 return cls(signer, **kwargs)
478
479 @classmethod
480 def from_service_account_info(cls, info, **kwargs):
481 """Creates a credentials instance from parsed service account info.
482
483 Args:
484 info (Mapping[str, str]): The service account info in Google
485 format.
486 kwargs: Additional arguments to pass to the constructor.
487
488 Returns:
489 google.auth.service_account.IDTokenCredentials: The constructed
490 credentials.
491
492 Raises:
493 ValueError: If the info is not in the expected format.
494 """
495 signer = _service_account_info.from_dict(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700496 info, require=["client_email", "token_uri"]
497 )
Christophe Tatonb649b432018-02-08 14:12:23 -0800498 return cls._from_signer_and_info(signer, info, **kwargs)
499
500 @classmethod
501 def from_service_account_file(cls, filename, **kwargs):
502 """Creates a credentials instance from a service account json file.
503
504 Args:
505 filename (str): The path to the service account json file.
506 kwargs: Additional arguments to pass to the constructor.
507
508 Returns:
509 google.auth.service_account.IDTokenCredentials: The constructed
510 credentials.
511 """
512 info, signer = _service_account_info.from_filename(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700513 filename, require=["client_email", "token_uri"]
514 )
Christophe Tatonb649b432018-02-08 14:12:23 -0800515 return cls._from_signer_and_info(signer, info, **kwargs)
516
517 def with_target_audience(self, target_audience):
518 """Create a copy of these credentials with the specified target
519 audience.
520
521 Args:
522 target_audience (str): The intended audience for these credentials,
523 used when requesting the ID Token.
524
525 Returns:
526 google.auth.service_account.IDTokenCredentials: A new credentials
527 instance.
528 """
529 return self.__class__(
530 self._signer,
531 service_account_email=self._service_account_email,
532 token_uri=self._token_uri,
533 target_audience=target_audience,
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700534 additional_claims=self._additional_claims.copy(),
Bu Sun Kim3dda7b22020-07-09 10:39:39 -0700535 quota_project_id=self.quota_project_id,
536 )
537
Bu Sun Kim41599ae2020-09-02 12:55:42 -0600538 @_helpers.copy_docstring(credentials.CredentialsWithQuotaProject)
Bu Sun Kim3dda7b22020-07-09 10:39:39 -0700539 def with_quota_project(self, quota_project_id):
540 return self.__class__(
541 self._signer,
542 service_account_email=self._service_account_email,
543 token_uri=self._token_uri,
544 target_audience=self._target_audience,
545 additional_claims=self._additional_claims.copy(),
546 quota_project_id=quota_project_id,
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700547 )
Christophe Tatonb649b432018-02-08 14:12:23 -0800548
549 def _make_authorization_grant_assertion(self):
550 """Create the OAuth 2.0 assertion.
551
552 This assertion is used during the OAuth 2.0 grant to acquire an
553 ID token.
554
555 Returns:
556 bytes: The authorization grant assertion.
557 """
558 now = _helpers.utcnow()
559 lifetime = datetime.timedelta(seconds=_DEFAULT_TOKEN_LIFETIME_SECS)
560 expiry = now + lifetime
561
562 payload = {
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700563 "iat": _helpers.datetime_to_secs(now),
564 "exp": _helpers.datetime_to_secs(expiry),
Christophe Tatonb649b432018-02-08 14:12:23 -0800565 # The issuer must be the service account email.
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700566 "iss": self.service_account_email,
Christophe Tatonb649b432018-02-08 14:12:23 -0800567 # The audience must be the auth token endpoint's URI
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700568 "aud": self._token_uri,
Christophe Tatonb649b432018-02-08 14:12:23 -0800569 # The target audience specifies which service the ID token is
570 # intended for.
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700571 "target_audience": self._target_audience,
Christophe Tatonb649b432018-02-08 14:12:23 -0800572 }
573
574 payload.update(self._additional_claims)
575
576 token = jwt.encode(self._signer, payload)
577
578 return token
579
580 @_helpers.copy_docstring(credentials.Credentials)
581 def refresh(self, request):
582 assertion = self._make_authorization_grant_assertion()
583 access_token, expiry, _ = _client.id_token_jwt_grant(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700584 request, self._token_uri, assertion
585 )
Christophe Tatonb649b432018-02-08 14:12:23 -0800586 self.token = access_token
587 self.expiry = expiry
588
589 @property
590 def service_account_email(self):
591 """The service account email."""
592 return self._service_account_email
593
594 @_helpers.copy_docstring(credentials.Signing)
595 def sign_bytes(self, message):
596 return self._signer.sign(message)
597
598 @property
599 @_helpers.copy_docstring(credentials.Signing)
600 def signer(self):
601 return self._signer
602
603 @property
604 @_helpers.copy_docstring(credentials.Signing)
605 def signer_email(self):
606 return self._service_account_email