Skip to content
This repository was archived by the owner on Mar 6, 2026. It is now read-only.

Commit 26a1637

Browse files
author
Jon Wayne Parrott
authored
Expose id_token in OAuth 2.0 credentials (#150)
1 parent cfbfd25 commit 26a1637

3 files changed

Lines changed: 27 additions & 7 deletions

File tree

google/oauth2/credentials.py

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,14 +39,16 @@
3939
class Credentials(credentials.Scoped, credentials.Credentials):
4040
"""Credentials using OAuth 2.0 access and refresh tokens."""
4141

42-
def __init__(self, token, refresh_token=None, token_uri=None,
43-
client_id=None, client_secret=None, scopes=None):
42+
def __init__(self, token, refresh_token=None, id_token=None,
43+
token_uri=None, client_id=None, client_secret=None,
44+
scopes=None):
4445
"""
4546
Args:
4647
token (Optional(str)): The OAuth 2.0 access token. Can be None
4748
if refresh information is provided.
4849
refresh_token (str): The OAuth 2.0 refresh token. If specified,
4950
credentials can be refreshed.
51+
id_token (str): The Open ID Connect ID Token.
5052
token_uri (str): The OAuth 2.0 authorization server's token
5153
endpoint URI. Must be specified for refresh, can be left as
5254
None if the token can not be refreshed.
@@ -63,6 +65,7 @@ def __init__(self, token, refresh_token=None, token_uri=None,
6365
super(Credentials, self).__init__()
6466
self.token = token
6567
self._refresh_token = refresh_token
68+
self._id_token = id_token
6669
self._scopes = scopes
6770
self._token_uri = token_uri
6871
self._client_id = client_id
@@ -79,6 +82,17 @@ def token_uri(self):
7982
URI."""
8083
return self._token_uri
8184

85+
@property
86+
def id_token(self):
87+
"""Optional[str]: The Open ID Connect ID Token.
88+
89+
Depending on the authorization server and the scopes requested, this
90+
may be populated when credentials are obtained and updated when
91+
:meth:`refresh` is called. This token is a JWT. It can be verified
92+
and decoded using :func:`google.oauth2.id_token.verify_oauth2_token`.
93+
"""
94+
return self._id_token
95+
8296
@property
8397
def client_id(self):
8498
"""Optional[str]: The OAuth 2.0 client ID."""
@@ -106,10 +120,12 @@ def with_scopes(self, scopes):
106120

107121
@_helpers.copy_docstring(credentials.Credentials)
108122
def refresh(self, request):
109-
access_token, refresh_token, expiry, _ = _client.refresh_grant(
110-
request, self._token_uri, self._refresh_token, self._client_id,
111-
self._client_secret)
123+
access_token, refresh_token, expiry, grant_response = (
124+
_client.refresh_grant(
125+
request, self._token_uri, self._refresh_token, self._client_id,
126+
self._client_secret))
112127

113128
self.token = access_token
114129
self.expiry = expiry
115130
self._refresh_token = refresh_token
131+
self._id_token = grant_response.get('id_token')

tests/oauth2/test_credentials.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ def test_create_scoped(self):
5858
def test_refresh_success(self, now_mock, refresh_grant_mock):
5959
token = 'token'
6060
expiry = _helpers.utcnow() + datetime.timedelta(seconds=500)
61+
grant_response = {'id_token': mock.sentinel.id_token}
6162
refresh_grant_mock.return_value = (
6263
# Access token
6364
token,
@@ -66,7 +67,7 @@ def test_refresh_success(self, now_mock, refresh_grant_mock):
6667
# Expiry,
6768
expiry,
6869
# Extra data
69-
{})
70+
grant_response)
7071
request_mock = mock.Mock()
7172

7273
# Refresh credentials
@@ -80,6 +81,7 @@ def test_refresh_success(self, now_mock, refresh_grant_mock):
8081
# Check that the credentials have the token and expiry
8182
assert self.credentials.token == token
8283
assert self.credentials.expiry == expiry
84+
assert self.credentials.id_token == mock.sentinel.id_token
8385

8486
# Check that the credentials are valid (have a token and are not
8587
# expired)

tests/oauth2/test_service_account.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,9 @@ def test__make_authorization_grant_assertion_subject(self):
162162
def test_refresh_success(self, jwt_grant_mock):
163163
token = 'token'
164164
jwt_grant_mock.return_value = (
165-
token, _helpers.utcnow() + datetime.timedelta(seconds=500), None)
165+
token,
166+
_helpers.utcnow() + datetime.timedelta(seconds=500),
167+
{})
166168
request_mock = mock.Mock()
167169

168170
# Refresh credentials

0 commit comments

Comments
 (0)