blob: 5113c992605bae624c9f270f7805c53c87dc164a [file] [log] [blame]
C.J. Collier37141e42020-02-13 13:49:49 -08001# Copyright 2016 Google LLC
Jon Wayne Parrotte2ab1002016-11-10 15:11:48 -08002#
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
Arlan Jaska4255b102018-02-08 15:51:26 -080015"""Google ID Token helpers.
16
17Provides support for verifying `OpenID Connect ID Tokens`_, especially ones
18generated by Google infrastructure.
19
20To parse and verify an ID Token issued by Google's OAuth 2.0 authorization
21server use :func:`verify_oauth2_token`. To verify an ID Token issued by
22Firebase, use :func:`verify_firebase_token`.
23
24A general purpose ID Token verifier is available as :func:`verify_token`.
25
26Example::
27
28 from google.oauth2 import id_token
29 from google.auth.transport import requests
30
31 request = requests.Request()
32
33 id_info = id_token.verify_oauth2_token(
34 token, request, 'my-client-id.example.com')
35
36 if id_info['iss'] != 'https://accounts.google.com':
37 raise ValueError('Wrong issuer.')
38
39 userid = id_info['sub']
40
41By default, this will re-fetch certificates for each verification. Because
42Google's public keys are only changed infrequently (on the order of once per
43day), you may wish to take advantage of caching to reduce latency and the
44potential for network errors. This can be accomplished using an external
45library like `CacheControl`_ to create a cache-aware
46:class:`google.auth.transport.Request`::
47
48 import cachecontrol
49 import google.auth.transport.requests
50 import requests
51
52 session = requests.session()
53 cached_session = cachecontrol.CacheControl(session)
54 request = google.auth.transport.requests.Request(session=cached_session)
55
56.. _OpenID Connect ID Token:
57 http://openid.net/specs/openid-connect-core-1_0.html#IDToken
58.. _CacheControl: https://cachecontrol.readthedocs.io
59"""
Jon Wayne Parrotte2ab1002016-11-10 15:11:48 -080060
61import json
62
63from six.moves import http_client
64
65from google.auth import exceptions
66from google.auth import jwt
67
68# The URL that provides public certificates for verifying ID tokens issued
69# by Google's OAuth 2.0 authorization server.
Bu Sun Kim054db752020-01-27 15:02:35 -080070_GOOGLE_OAUTH2_CERTS_URL = "https://www.googleapis.com/oauth2/v3/certs"
Jon Wayne Parrotte2ab1002016-11-10 15:11:48 -080071
72# The URL that provides public certificates for verifying ID tokens issued
73# by Firebase and the Google APIs infrastructure
74_GOOGLE_APIS_CERTS_URL = (
Bu Sun Kim9eec0912019-10-21 17:04:21 -070075 "https://www.googleapis.com/robot/v1/metadata/x509"
76 "/securetoken@system.gserviceaccount.com"
77)
Jon Wayne Parrotte2ab1002016-11-10 15:11:48 -080078
79
80def _fetch_certs(request, certs_url):
81 """Fetches certificates.
82
83 Google-style cerificate endpoints return JSON in the format of
84 ``{'key id': 'x509 certificate'}``.
85
86 Args:
87 request (google.auth.transport.Request): The object used to make
88 HTTP requests.
89 certs_url (str): The certificate endpoint URL.
90
91 Returns:
92 Mapping[str, str]: A mapping of public key ID to x.509 certificate
93 data.
94 """
Bu Sun Kim9eec0912019-10-21 17:04:21 -070095 response = request(certs_url, method="GET")
Jon Wayne Parrotte2ab1002016-11-10 15:11:48 -080096
97 if response.status != http_client.OK:
98 raise exceptions.TransportError(
Bu Sun Kim9eec0912019-10-21 17:04:21 -070099 "Could not fetch certificates at {}".format(certs_url)
100 )
Jon Wayne Parrotte2ab1002016-11-10 15:11:48 -0800101
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700102 return json.loads(response.data.decode("utf-8"))
Jon Wayne Parrotte2ab1002016-11-10 15:11:48 -0800103
104
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700105def verify_token(id_token, request, audience=None, certs_url=_GOOGLE_OAUTH2_CERTS_URL):
Jon Wayne Parrotte2ab1002016-11-10 15:11:48 -0800106 """Verifies an ID token and returns the decoded token.
107
108 Args:
109 id_token (Union[str, bytes]): The encoded token.
110 request (google.auth.transport.Request): The object used to make
111 HTTP requests.
112 audience (str): The audience that this token is intended for. If None
113 then the audience is not verified.
114 certs_url (str): The URL that specifies the certificates to use to
115 verify the token. This URL should return JSON in the format of
116 ``{'key id': 'x509 certificate'}``.
117
118 Returns:
119 Mapping[str, Any]: The decoded token.
120 """
121 certs = _fetch_certs(request, certs_url)
122
123 return jwt.decode(id_token, certs=certs, audience=audience)
124
125
126def verify_oauth2_token(id_token, request, audience=None):
127 """Verifies an ID Token issued by Google's OAuth 2.0 authorization server.
128
129 Args:
130 id_token (Union[str, bytes]): The encoded token.
131 request (google.auth.transport.Request): The object used to make
132 HTTP requests.
133 audience (str): The audience that this token is intended for. This is
134 typically your application's OAuth 2.0 client ID. If None then the
135 audience is not verified.
136
137 Returns:
138 Mapping[str, Any]: The decoded token.
139 """
140 return verify_token(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700141 id_token, request, audience=audience, certs_url=_GOOGLE_OAUTH2_CERTS_URL
142 )
Jon Wayne Parrotte2ab1002016-11-10 15:11:48 -0800143
144
145def verify_firebase_token(id_token, request, audience=None):
146 """Verifies an ID Token issued by Firebase Authentication.
147
148 Args:
149 id_token (Union[str, bytes]): The encoded token.
150 request (google.auth.transport.Request): The object used to make
151 HTTP requests.
152 audience (str): The audience that this token is intended for. This is
153 typically your Firebase application ID. If None then the audience
154 is not verified.
155
156 Returns:
157 Mapping[str, Any]: The decoded token.
158 """
159 return verify_token(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700160 id_token, request, audience=audience, certs_url=_GOOGLE_APIS_CERTS_URL
161 )