blob: 208ab62240d63805cc0ebfca200598e45964bdc3 [file] [log] [blame]
Jon Wayne Parrotte2ab1002016-11-10 15:11:48 -08001# Copyright 2016 Google Inc.
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
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.
70_GOOGLE_OAUTH2_CERTS_URL = 'https://www.googleapis.com/oauth2/v1/certs'
71
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 = (
75 'https://www.googleapis.com/robot/v1/metadata/x509'
76 '/securetoken@system.gserviceaccount.com')
77
78
79def _fetch_certs(request, certs_url):
80 """Fetches certificates.
81
82 Google-style cerificate endpoints return JSON in the format of
83 ``{'key id': 'x509 certificate'}``.
84
85 Args:
86 request (google.auth.transport.Request): The object used to make
87 HTTP requests.
88 certs_url (str): The certificate endpoint URL.
89
90 Returns:
91 Mapping[str, str]: A mapping of public key ID to x.509 certificate
92 data.
93 """
Jon Wayne Parrott97eb8702016-11-17 09:43:16 -080094 response = request(certs_url, method='GET')
Jon Wayne Parrotte2ab1002016-11-10 15:11:48 -080095
96 if response.status != http_client.OK:
97 raise exceptions.TransportError(
98 'Could not fetch certificates at {}'.format(certs_url))
99
100 return json.loads(response.data.decode('utf-8'))
101
102
103def verify_token(id_token, request, audience=None,
104 certs_url=_GOOGLE_OAUTH2_CERTS_URL):
105 """Verifies an ID token and returns the decoded token.
106
107 Args:
108 id_token (Union[str, bytes]): The encoded token.
109 request (google.auth.transport.Request): The object used to make
110 HTTP requests.
111 audience (str): The audience that this token is intended for. If None
112 then the audience is not verified.
113 certs_url (str): The URL that specifies the certificates to use to
114 verify the token. This URL should return JSON in the format of
115 ``{'key id': 'x509 certificate'}``.
116
117 Returns:
118 Mapping[str, Any]: The decoded token.
119 """
120 certs = _fetch_certs(request, certs_url)
121
122 return jwt.decode(id_token, certs=certs, audience=audience)
123
124
125def verify_oauth2_token(id_token, request, audience=None):
126 """Verifies an ID Token issued by Google's OAuth 2.0 authorization server.
127
128 Args:
129 id_token (Union[str, bytes]): The encoded token.
130 request (google.auth.transport.Request): The object used to make
131 HTTP requests.
132 audience (str): The audience that this token is intended for. This is
133 typically your application's OAuth 2.0 client ID. If None then the
134 audience is not verified.
135
136 Returns:
137 Mapping[str, Any]: The decoded token.
138 """
139 return verify_token(
140 id_token, request, audience=audience,
141 certs_url=_GOOGLE_OAUTH2_CERTS_URL)
142
143
144def verify_firebase_token(id_token, request, audience=None):
145 """Verifies an ID Token issued by Firebase Authentication.
146
147 Args:
148 id_token (Union[str, bytes]): The encoded token.
149 request (google.auth.transport.Request): The object used to make
150 HTTP requests.
151 audience (str): The audience that this token is intended for. This is
152 typically your Firebase application ID. If None then the audience
153 is not verified.
154
155 Returns:
156 Mapping[str, Any]: The decoded token.
157 """
158 return verify_token(
159 id_token, request, audience=audience, certs_url=_GOOGLE_APIS_CERTS_URL)