1 # -*- coding: utf-8 -*-
3 oauthlib.oauth2.rfc6749
4 ~~~~~~~~~~~~~~~~~~~~~~~
6 This module is an implementation of various logic needed
7 for consuming and providing OAuth 2.0 RFC6749.
9 from __future__ import absolute_import, unicode_literals
13 from oauthlib.common import to_unicode
15 from .base import Client
16 from ..parameters import prepare_token_request
17 from ..parameters import parse_token_response
20 class ServiceApplicationClient(Client):
21 """A public client utilizing the JWT bearer grant.
23 JWT bearer tokes can be used to request an access token when a client
24 wishes to utilize an existing trust relationship, expressed through the
25 semantics of (and digital signature or keyed message digest calculated
26 over) the JWT, without a direct user approval step at the authorization
29 This grant type does not involve an authorization step. It may be
30 used by both public and confidential clients.
33 grant_type = 'urn:ietf:params:oauth:grant-type:jwt-bearer'
35 def __init__(self, client_id, private_key=None, subject=None, issuer=None,
36 audience=None, **kwargs):
37 """Initalize a JWT client with defaults for implicit use later.
39 :param client_id: Client identifier given by the OAuth provider upon
42 :param private_key: Private key used for signing and encrypting.
43 Must be given as a string.
45 :param subject: The principal that is the subject of the JWT, i.e.
46 which user is the token requested on behalf of.
47 For example, ``foo@example.com.
49 :param issuer: The JWT MUST contain an "iss" (issuer) claim that
50 contains a unique identifier for the entity that issued
51 the JWT. For example, ``your-client@provider.com``.
53 :param audience: A value identifying the authorization server as an
54 intended audience, e.g.
55 ``https://provider.com/oauth2/token``.
57 :param kwargs: Additional arguments to pass to base client, such as
58 state and token. See Client.__init__.__doc__ for
61 super(ServiceApplicationClient, self).__init__(client_id, **kwargs)
62 self.private_key = private_key
63 self.subject = subject
65 self.audience = audience
67 def prepare_request_body(self,
78 """Create and add a JWT assertion to the request body.
80 :param private_key: Private key used for signing and encrypting.
81 Must be given as a string.
83 :param subject: (sub) The principal that is the subject of the JWT,
84 i.e. which user is the token requested on behalf of.
85 For example, ``foo@example.com.
87 :param issuer: (iss) The JWT MUST contain an "iss" (issuer) claim that
88 contains a unique identifier for the entity that issued
89 the JWT. For example, ``your-client@provider.com``.
91 :param audience: (aud) A value identifying the authorization server as an
92 intended audience, e.g.
93 ``https://provider.com/oauth2/token``.
95 :param expires_at: A unix expiration timestamp for the JWT. Defaults
96 to an hour from now, i.e. ``time.time() + 3600``.
98 :param issued_at: A unix timestamp of when the JWT was created.
99 Defaults to now, i.e. ``time.time()``.
101 :param not_before: A unix timestamp after which the JWT may be used.
102 Not included unless provided.
104 :param jwt_id: A unique JWT token identifier. Not included unless
107 :param extra_claims: A dict of additional claims to include in the JWT.
109 :param scope: The scope of the access request.
111 :param body: Request body (string) with extra parameters.
113 :param kwargs: Extra credentials to include in the token request.
115 The "scope" parameter may be used, as defined in the Assertion
116 Framework for OAuth 2.0 Client Authentication and Authorization Grants
117 [I-D.ietf-oauth-assertions] specification, to indicate the requested
120 Authentication of the client is optional, as described in
121 `Section 3.2.1`_ of OAuth 2.0 [RFC6749] and consequently, the
122 "client_id" is only needed when a form of client authentication that
123 relies on the parameter is used.
125 The following non-normative example demonstrates an Access Token
126 Request with a JWT as an authorization grant (with extra line breaks
127 for display purposes only):
131 POST /token.oauth2 HTTP/1.1
133 Content-Type: application/x-www-form-urlencoded
135 grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer
136 &assertion=eyJhbGciOiJFUzI1NiJ9.
137 eyJpc3Mi[...omitted for brevity...].
138 J9l-ZhwP[...omitted for brevity...]
140 .. _`Section 3.2.1`: http://tools.ietf.org/html/rfc6749#section-3.2.1
144 key = private_key or self.private_key
146 raise ValueError('An encryption key must be supplied to make JWT'
149 'iss': issuer or self.issuer,
150 'aud': audience or self.issuer,
151 'sub': subject or self.issuer,
152 'exp': int(expires_at or time.time() + 3600),
153 'iat': int(issued_at or time.time()),
156 for attr in ('iss', 'aud', 'sub'):
157 if claim[attr] is None:
159 'Claim must include %s but none was given.' % attr)
161 if 'not_before' in kwargs:
162 claim['nbf'] = kwargs.pop('not_before')
164 if 'jwt_id' in kwargs:
165 claim['jti'] = kwargs.pop('jwt_id')
167 claim.update(extra_claims or {})
169 assertion = jwt.encode(claim, key, 'RS256')
170 assertion = to_unicode(assertion)
172 return prepare_token_request(self.grant_type,