1 # Copyright 2020 Google LLC 2 # 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 """OAuth 2.0 Async Credentials. 16 17 This module provides credentials based on OAuth 2.0 access and refresh tokens. 18 These credentials usually access resources on behalf of a user (resource 19 owner). 20 21 Specifically, this is intended to use access tokens acquired using the 22 `Authorization Code grant`_ and can refresh those tokens using a 23 optional `refresh token`_. 24 25 Obtaining the initial access and refresh token is outside of the scope of this 26 module. Consult `rfc6749 section 4.1`_ for complete details on the 27 Authorization Code grant flow. 28 29 .. _Authorization Code grant: https://tools.ietf.org/html/rfc6749#section-1.3.1 30 .. _refresh token: https://tools.ietf.org/html/rfc6749#section-6 31 .. _rfc6749 section 4.1: https://tools.ietf.org/html/rfc6749#section-4.1 32 """ 33 34 from google.auth import _credentials_async as credentials 35 from google.auth import _helpers 36 from google.auth import exceptions 37 from google.oauth2 import _reauth_async as reauth 38 from google.oauth2 import credentials as oauth2_credentials 39 40 41 class Credentials(oauth2_credentials.Credentials): 42 """Credentials using OAuth 2.0 access and refresh tokens. 43 44 The credentials are considered immutable. If you want to modify the 45 quota project, use :meth:`with_quota_project` or :: 46 47 credentials = credentials.with_quota_project('myproject-123) 48 """ 49 50 @_helpers.copy_docstring(credentials.Credentials) 51 async def refresh(self, request): 52 if ( 53 self._refresh_token is None 54 or self._token_uri is None 55 or self._client_id is None 56 or self._client_secret is None 57 ): 58 raise exceptions.RefreshError( 59 "The credentials do not contain the necessary fields need to " 60 "refresh the access token. You must specify refresh_token, " 61 "token_uri, client_id, and client_secret." 62 ) 63 64 ( 65 access_token, 66 refresh_token, 67 expiry, 68 grant_response, 69 rapt_token, 70 ) = await reauth.refresh_grant( 71 request, 72 self._token_uri, 73 self._refresh_token, 74 self._client_id, 75 self._client_secret, 76 scopes=self._scopes, 77 rapt_token=self._rapt_token, 78 enable_reauth_refresh=self._enable_reauth_refresh, 79 ) 80 81 self.token = access_token 82 self.expiry = expiry 83 self._refresh_token = refresh_token 84 self._id_token = grant_response.get("id_token") 85 self._rapt_token = rapt_token 86 87 if self._scopes and "scope" in grant_response: 88 requested_scopes = frozenset(self._scopes) 89 granted_scopes = frozenset(grant_response["scope"].split()) 90 scopes_requested_but_not_granted = requested_scopes - granted_scopes 91 if scopes_requested_but_not_granted: 92 raise exceptions.RefreshError( 93 "Not all requested scopes were granted by the " 94 "authorization server, missing scopes {}.".format( 95 ", ".join(scopes_requested_but_not_granted) 96 ) 97 ) 98 99 100 class UserAccessTokenCredentials(oauth2_credentials.UserAccessTokenCredentials): 101 """Access token credentials for user account. 102 103 Obtain the access token for a given user account or the current active 104 user account with the ``gcloud auth print-access-token`` command. 105 106 Args: 107 account (Optional[str]): Account to get the access token for. If not 108 specified, the current active account will be used. 109 quota_project_id (Optional[str]): The project ID used for quota 110 and billing. 111 112 """ 113