Skip to content

Commit 0a423d4

Browse files
authored
Merge pull request #844 from azmeuk/806-get-jwt-config-client
`get_jwt_config` takes a `client` parameter.
2 parents 2808378 + 714502a commit 0a423d4

File tree

8 files changed

+151
-16
lines changed

8 files changed

+151
-16
lines changed

authlib/oidc/core/grants/code.py

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
"""
99

1010
import logging
11+
import warnings
1112

1213
from authlib.oauth2.rfc6749 import OAuth2Request
1314

@@ -20,7 +21,7 @@
2021

2122

2223
class OpenIDToken:
23-
def get_jwt_config(self, grant): # pragma: no cover
24+
def get_jwt_config(self, grant, client): # pragma: no cover
2425
"""Get the JWT configuration for OpenIDCode extension. The JWT
2526
configuration will be used to generate ``id_token``.
2627
If ``alg`` is undefined, the ``id_token_signed_response_alg`` client
@@ -29,15 +30,16 @@ def get_jwt_config(self, grant): # pragma: no cover
2930
will be used.
3031
Developers MUST implement this method in subclass, e.g.::
3132
32-
def get_jwt_config(self, grant):
33+
def get_jwt_config(self, grant, client):
3334
return {
3435
"key": read_private_key_file(key_path),
35-
"alg": "RS256",
36+
"alg": client.id_token_signed_response_alg or "RS256",
3637
"iss": "issuer-identity",
3738
"exp": 3600,
3839
}
3940
4041
:param grant: AuthorizationCodeGrant instance
42+
:param client: OAuth2 client instance
4143
:return: dict
4244
"""
4345
raise NotImplementedError()
@@ -78,7 +80,17 @@ def process_token(self, grant, response):
7880
request: OAuth2Request = grant.request
7981
authorization_code = request.authorization_code
8082

81-
config = self.get_jwt_config(grant)
83+
try:
84+
config = self.get_jwt_config(grant, request.client)
85+
except TypeError:
86+
warnings.warn(
87+
"get_jwt_config(self, grant) is deprecated and will be removed in version 1.8. "
88+
"Use get_jwt_config(self, grant, client) instead.",
89+
DeprecationWarning,
90+
stacklevel=2,
91+
)
92+
config = self.get_jwt_config(grant)
93+
8294
config["aud"] = self.get_audiences(request)
8395

8496
# Per OpenID Connect Registration 1.0 Section 2:

authlib/oidc/core/grants/implicit.py

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import logging
2+
import warnings
23

34
from authlib.oauth2.rfc6749 import AccessDeniedError
45
from authlib.oauth2.rfc6749 import ImplicitGrant
@@ -36,19 +37,20 @@ def exists_nonce(self, nonce, request):
3637
"""
3738
raise NotImplementedError()
3839

39-
def get_jwt_config(self):
40+
def get_jwt_config(self, client):
4041
"""Get the JWT configuration for OpenIDImplicitGrant. The JWT
4142
configuration will be used to generate ``id_token``. Developers
4243
MUST implement this method in subclass, e.g.::
4344
44-
def get_jwt_config(self):
45+
def get_jwt_config(self, client):
4546
return {
4647
"key": read_private_key_file(key_path),
47-
"alg": "RS256",
48+
"alg": client.id_token_signed_response_alg or "RS256",
4849
"iss": "issuer-identity",
4950
"exp": 3600,
5051
}
5152
53+
:param client: OAuth2 client instance
5254
:return: dict
5355
"""
5456
raise NotImplementedError()
@@ -143,7 +145,17 @@ def create_granted_params(self, grant_user):
143145
return params
144146

145147
def process_implicit_token(self, token, code=None):
146-
config = self.get_jwt_config()
148+
try:
149+
config = self.get_jwt_config(self.request.client)
150+
except TypeError:
151+
warnings.warn(
152+
"get_jwt_config(self) is deprecated and will be removed in version 1.8. "
153+
"Use get_jwt_config(self, client) instead.",
154+
DeprecationWarning,
155+
stacklevel=2,
156+
)
157+
config = self.get_jwt_config()
158+
147159
config["aud"] = self.get_audiences(self.request)
148160
config["nonce"] = self.request.payload.data.get("nonce")
149161
if code is not None:

docs/changelog.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,13 @@ Changelog
66

77
Here you can see the full list of changes between each Authlib release.
88

9+
Version 1.6.6
10+
-------------
11+
12+
**Released on Dec 11, 2025**
13+
14+
- ``get_jwt_config`` takes a ``client`` parameter.
15+
916
Version 1.6.5
1017
-------------
1118

tests/clients/test_requests/test_oauth2_session.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -324,16 +324,16 @@ def test_token_status3():
324324

325325

326326
def test_expires_in_used_when_expires_at_unparseable():
327-
"""Test that expires_in is used as fallback when expires_at is unparseable."""
327+
"""Test that expires_in is used as fallback when expires_at is unparsable."""
328328
token = dict(
329329
access_token="a",
330330
token_type="bearer",
331331
expires_in=3600, # 1 hour from now
332-
expires_at="2024-01-01T00:00:00Z", # Unparseable - should fall back to expires_in
332+
expires_at="2024-01-01T00:00:00Z", # Unparsable - should fall back to expires_in
333333
)
334334
sess = OAuth2Session("foo", token=token)
335335

336-
# The token should use expires_in since expires_at is unparseable
336+
# The token should use expires_in since expires_at is unparsable
337337
# So it should be considered expired with leeway > 3600
338338
assert sess.token.is_expired(leeway=3700) is True
339339
# And not expired with leeway < 3600

tests/flask/test_oauth2/test_openid_code_grant.py

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
from authlib.oidc.core.grants import OpenIDCode as _OpenIDCode
1616
from tests.util import read_file_path
1717

18+
from .models import Client
1819
from .models import CodeGrantMixin
1920
from .models import exists_nonce
2021
from .models import save_authorization_code
@@ -54,7 +55,7 @@ def save_authorization_code(self, code, request):
5455
return save_authorization_code(code, request)
5556

5657
class OpenIDCode(_OpenIDCode):
57-
def get_jwt_config(self, grant):
58+
def get_jwt_config(self, grant, client):
5859
key = current_app.config.get("OAUTH2_JWT_KEY")
5960
alg = current_app.config.get("OAUTH2_JWT_ALG")
6061
iss = current_app.config.get("OAUTH2_JWT_ISS")
@@ -419,3 +420,64 @@ def test_authorize_token_algs(test_client, server, app, alg, private_key, public
419420
claims_options={"iss": {"value": "Authlib"}},
420421
)
421422
claims.validate()
423+
424+
425+
def test_deprecated_get_jwt_config_signature(test_client, server, db, user):
426+
"""Using the old get_jwt_config(self, grant) signature should emit a DeprecationWarning."""
427+
428+
class DeprecatedOpenIDCode(_OpenIDCode):
429+
def get_jwt_config(self, grant):
430+
return {"key": "secret", "alg": "HS256", "iss": "Authlib", "exp": 3600}
431+
432+
def exists_nonce(self, nonce, request):
433+
return exists_nonce(nonce, request)
434+
435+
def generate_user_info(self, user, scopes):
436+
return user.generate_user_info(scopes)
437+
438+
class AuthorizationCodeGrant(CodeGrantMixin, _AuthorizationCodeGrant):
439+
def save_authorization_code(self, code, request):
440+
return save_authorization_code(code, request)
441+
442+
server.register_grant(AuthorizationCodeGrant, [DeprecatedOpenIDCode()])
443+
444+
client = Client(
445+
user_id=user.id,
446+
client_id="deprecated-client",
447+
client_secret="secret",
448+
)
449+
client.set_client_metadata(
450+
{
451+
"redirect_uris": ["https://client.test"],
452+
"scope": "openid profile",
453+
"response_types": ["code"],
454+
"grant_types": ["authorization_code"],
455+
}
456+
)
457+
db.session.add(client)
458+
db.session.commit()
459+
460+
rv = test_client.post(
461+
"/oauth/authorize",
462+
data={
463+
"response_type": "code",
464+
"client_id": "deprecated-client",
465+
"state": "bar",
466+
"scope": "openid profile",
467+
"redirect_uri": "https://client.test",
468+
"user_id": "1",
469+
},
470+
)
471+
params = dict(url_decode(urlparse.urlparse(rv.location).query))
472+
code = params["code"]
473+
474+
with pytest.warns(DeprecationWarning, match="get_jwt_config.*version 1.8"):
475+
test_client.post(
476+
"/oauth/token",
477+
data={
478+
"grant_type": "authorization_code",
479+
"redirect_uri": "https://client.test",
480+
"code": code,
481+
},
482+
headers=create_basic_header("deprecated-client", "secret"),
483+
)

tests/flask/test_oauth2/test_openid_hybrid_grant.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ def save_authorization_code(self, code, request):
2626
return save_authorization_code(code, request)
2727

2828
class OpenIDCode(_OpenIDCode):
29-
def get_jwt_config(self, grant):
29+
def get_jwt_config(self, grant, client):
3030
return dict(JWT_CONFIG)
3131

3232
def exists_nonce(self, nonce, request):
@@ -39,7 +39,7 @@ class OpenIDHybridGrant(_OpenIDHybridGrant):
3939
def save_authorization_code(self, code, request):
4040
return save_authorization_code(code, request)
4141

42-
def get_jwt_config(self):
42+
def get_jwt_config(self, client):
4343
return dict(JWT_CONFIG)
4444

4545
def exists_nonce(self, nonce, request):

tests/flask/test_oauth2/test_openid_implict_grant.py

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,12 @@
55
from authlib.common.urls import url_decode
66
from authlib.common.urls import urlparse
77
from authlib.jose import JsonWebToken
8+
from authlib.oauth2.rfc6749.requests import BasicOAuth2Payload
9+
from authlib.oauth2.rfc6749.requests import OAuth2Request
810
from authlib.oidc.core import ImplicitIDToken
911
from authlib.oidc.core.grants import OpenIDImplicitGrant as _OpenIDImplicitGrant
1012

13+
from .models import Client
1114
from .models import exists_nonce
1215

1316
authorize_url = "/oauth/authorize?response_type=token&client_id=client-id"
@@ -16,7 +19,7 @@
1619
@pytest.fixture(autouse=True)
1720
def server(server):
1821
class OpenIDImplicitGrant(_OpenIDImplicitGrant):
19-
def get_jwt_config(self):
22+
def get_jwt_config(self, client):
2023
alg = current_app.config.get("OAUTH2_JWT_ALG", "HS256")
2124
return dict(key="secret", alg=alg, iss="Authlib", exp=3600)
2225

@@ -259,3 +262,42 @@ def test_client_metadata_alg_none(test_client, app, db, client):
259262
)
260263
params = dict(url_decode(urlparse.urlparse(rv.location).fragment))
261264
assert params["error"] == "invalid_request"
265+
266+
267+
def test_deprecated_get_jwt_config_signature(user):
268+
"""Using the old get_jwt_config(self) signature should emit a DeprecationWarning."""
269+
270+
class DeprecatedImplicitGrant(_OpenIDImplicitGrant):
271+
def get_jwt_config(self):
272+
return {"key": "secret", "alg": "HS256", "iss": "Authlib", "exp": 3600}
273+
274+
def generate_user_info(self, user, scopes):
275+
return user.generate_user_info(scopes)
276+
277+
def exists_nonce(self, nonce, request):
278+
return exists_nonce(nonce, request)
279+
280+
client = Client(
281+
user_id=user.id,
282+
client_id="deprecated-client",
283+
client_secret="secret",
284+
)
285+
client.set_client_metadata(
286+
{
287+
"redirect_uris": ["https://client.test/callback"],
288+
"scope": "openid profile",
289+
"token_endpoint_auth_method": "none",
290+
"response_types": ["id_token"],
291+
}
292+
)
293+
294+
request = OAuth2Request("POST", "https://server.test/authorize")
295+
request.payload = BasicOAuth2Payload({"nonce": "test-nonce"})
296+
request.client = client
297+
request.user = user
298+
299+
grant = DeprecatedImplicitGrant(request, client)
300+
token = {"scope": "openid", "expires_in": 3600}
301+
302+
with pytest.warns(DeprecationWarning, match="get_jwt_config.*version 1.8"):
303+
grant.process_implicit_token(token)

tests/flask/test_oauth2/test_password_grant.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ def client(client, db):
2626

2727

2828
class IDToken(OpenIDToken):
29-
def get_jwt_config(self, grant):
29+
def get_jwt_config(self, grant, client):
3030
return {
3131
"iss": "Authlib",
3232
"key": "secret",

0 commit comments

Comments
 (0)