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"""JSON Web Tokens
16
17Provides support for creating (encoding) and verifying (decoding) JWTs,
18especially JWTs generated and consumed by Google infrastructure.
19
20See `rfc7519`_ for more details on JWTs.
21
22To encode a JWT use :func:`encode`::
23
24    from google.auth import crypt
25    from google.auth import jwt_async
26
27    signer = crypt.Signer(private_key)
28    payload = {'some': 'payload'}
29    encoded = jwt_async.encode(signer, payload)
30
31To decode a JWT and verify claims use :func:`decode`::
32
33    claims = jwt_async.decode(encoded, certs=public_certs)
34
35You can also skip verification::
36
37    claims = jwt_async.decode(encoded, verify=False)
38
39.. _rfc7519: https://tools.ietf.org/html/rfc7519
40
41
42NOTE: This async support is experimental and marked internal. This surface may
43change in minor releases.
44"""
45
46import google.auth
47from google.auth import jwt
48
49
50def encode(signer, payload, header=None, key_id=None):
51    """Make a signed JWT.
52
53    Args:
54        signer (google.auth.crypt.Signer): The signer used to sign the JWT.
55        payload (Mapping[str, str]): The JWT payload.
56        header (Mapping[str, str]): Additional JWT header payload.
57        key_id (str): The key id to add to the JWT header. If the
58            signer has a key id it will be used as the default. If this is
59            specified it will override the signer's key id.
60
61    Returns:
62        bytes: The encoded JWT.
63    """
64    return jwt.encode(signer, payload, header, key_id)
65
66
67def decode(token, certs=None, verify=True, audience=None):
68    """Decode and verify a JWT.
69
70    Args:
71        token (str): The encoded JWT.
72        certs (Union[str, bytes, Mapping[str, Union[str, bytes]]]): The
73            certificate used to validate the JWT signature. If bytes or string,
74            it must the the public key certificate in PEM format. If a mapping,
75            it must be a mapping of key IDs to public key certificates in PEM
76            format. The mapping must contain the same key ID that's specified
77            in the token's header.
78        verify (bool): Whether to perform signature and claim validation.
79            Verification is done by default.
80        audience (str): The audience claim, 'aud', that this JWT should
81            contain. If None then the JWT's 'aud' parameter is not verified.
82
83    Returns:
84        Mapping[str, str]: The deserialized JSON payload in the JWT.
85
86    Raises:
87        ValueError: if any verification checks failed.
88    """
89
90    return jwt.decode(token, certs, verify, audience)
91
92
93class Credentials(
94    jwt.Credentials,
95    google.auth._credentials_async.Signing,
96    google.auth._credentials_async.Credentials,
97):
98    """Credentials that use a JWT as the bearer token.
99
100    These credentials require an "audience" claim. This claim identifies the
101    intended recipient of the bearer token.
102
103    The constructor arguments determine the claims for the JWT that is
104    sent with requests. Usually, you'll construct these credentials with
105    one of the helper constructors as shown in the next section.
106
107    To create JWT credentials using a Google service account private key
108    JSON file::
109
110        audience = 'https://pubsub.googleapis.com/google.pubsub.v1.Publisher'
111        credentials = jwt_async.Credentials.from_service_account_file(
112            'service-account.json',
113            audience=audience)
114
115    If you already have the service account file loaded and parsed::
116
117        service_account_info = json.load(open('service_account.json'))
118        credentials = jwt_async.Credentials.from_service_account_info(
119            service_account_info,
120            audience=audience)
121
122    Both helper methods pass on arguments to the constructor, so you can
123    specify the JWT claims::
124
125        credentials = jwt_async.Credentials.from_service_account_file(
126            'service-account.json',
127            audience=audience,
128            additional_claims={'meta': 'data'})
129
130    You can also construct the credentials directly if you have a
131    :class:`~google.auth.crypt.Signer` instance::
132
133        credentials = jwt_async.Credentials(
134            signer,
135            issuer='your-issuer',
136            subject='your-subject',
137            audience=audience)
138
139    The claims are considered immutable. If you want to modify the claims,
140    you can easily create another instance using :meth:`with_claims`::
141
142        new_audience = (
143            'https://pubsub.googleapis.com/google.pubsub.v1.Subscriber')
144        new_credentials = credentials.with_claims(audience=new_audience)
145    """
146
147
148class OnDemandCredentials(
149    jwt.OnDemandCredentials,
150    google.auth._credentials_async.Signing,
151    google.auth._credentials_async.Credentials,
152):
153    """On-demand JWT credentials.
154
155    Like :class:`Credentials`, this class uses a JWT as the bearer token for
156    authentication. However, this class does not require the audience at
157    construction time. Instead, it will generate a new token on-demand for
158    each request using the request URI as the audience. It caches tokens
159    so that multiple requests to the same URI do not incur the overhead
160    of generating a new token every time.
161
162    This behavior is especially useful for `gRPC`_ clients. A gRPC service may
163    have multiple audience and gRPC clients may not know all of the audiences
164    required for accessing a particular service. With these credentials,
165    no knowledge of the audiences is required ahead of time.
166
167    .. _grpc: http://www.grpc.io/
168    """
169