Skip to content

Commit 0965100

Browse files
gardenerikn2ygk
andauthored
Allow the use of unhashed secrets (#1311)
* enable configuration of Applications to keep the client_secret unhashed to enable properly signed JWTs --------- Co-authored-by: Alan Crosswell <[email protected]> Co-authored-by: Alan Crosswell <[email protected]>
1 parent f8c9f36 commit 0965100

16 files changed

+145
-5
lines changed

AUTHORS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ Contributors
99

1010
Abhishek Patel
1111
Adam Johnson
12+
Adam Zahradník
1213
Adheeth P Praveen
1314
Alan Crosswell
1415
Alejandro Mantecon Guillen

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2020
* #1185 Add middleware for adding access token to request
2121
* #1273 Add caching of loading of OIDC private key.
2222
* #1285 Add post_logout_redirect_uris field in application views.
23+
* #1311 Add option to disable client_secret hashing to allow verifying JWTs' signatures.
2324

2425
- ### Fixed
2526
* #1284 Allow to logout whith no id_token_hint even if the browser session already expired
-234 Bytes
Loading
462 Bytes
Loading

docs/getting_started.rst

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,9 @@ Start the development server::
244244

245245
Point your browser to http://127.0.0.1:8000/o/applications/register/ lets create an application.
246246

247-
Fill the form as show in the screenshot below and before save take note of ``Client id`` and ``Client secret`` we will use it in a minute.
247+
Fill the form as show in the screenshot below and before save take note of ``Client id`` and ``Client secret``, we will use it in a minute.
248+
249+
If you want to use this application with OIDC and ``HS256`` (see :doc:`OpenID Connect <oidc>`), uncheck ``Hash client secret`` to allow verifying tokens using JWT signatures. This means your client secret will be stored in cleartext but is the only way to successfully use signed JWT's.
248250

249251
.. image:: _images/application-register-auth-code.png
250252
:alt: Authorization code application registration

docs/oidc.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,9 @@ If you would prefer to use just ``HS256`` keys, you don't need to create any
133133
additional keys, ``django-oauth-toolkit`` will just use the application's
134134
``client_secret`` to sign the JWT token.
135135

136+
To be able to verify the JWT's signature using the ``client_secret``, you
137+
must set the application's ``hash_client_secret`` to ``False``.
138+
136139
In this case, you just need to enable OIDC and add ``openid`` to your list of
137140
scopes in your ``settings.py``::
138141

docs/tutorial/tutorial_01.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,11 @@ point your browser to http://localhost:8000/o/applications/ and add an Applicati
9999
* `Name`: this is the name of the client application on the server, and will be displayed on the authorization request
100100
page, where users can allow/deny access to their data.
101101

102+
* `Hash client secret`: checking this hashes the client secret on save so it cannot be retrieved later. This should be
103+
unchecked if you plan to use OIDC with ``HS256`` and want to check the tokens' signatures using JWT. Otherwise,
104+
Django OAuth Toolkit cannot use `Client Secret` to sign the tokens (as it cannot be retrieved later) and the hashed
105+
value will be used when signing. This may lead to incompatibilities with some OIDC Relying Party libraries.
106+
102107
Take note of the `Client id` and the `Client Secret` then logout (this is needed only for testing the authorization
103108
process we'll explain shortly)
104109

oauth2_provider/management/commands/createapplication.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,13 @@ def add_arguments(self, parser):
4848
type=str,
4949
help="The secret for this application",
5050
)
51+
parser.add_argument(
52+
"--no-hash-client-secret",
53+
dest="hash_client_secret",
54+
action="store_false",
55+
help="Don't hash the client secret",
56+
)
57+
parser.set_defaults(hash_client_secret=True)
5158
parser.add_argument(
5259
"--name",
5360
type=str,
@@ -74,7 +81,7 @@ def handle(self, *args, **options):
7481
# Data in options must be cleaned because there are unneeded key-value like
7582
# verbosity and others. Also do not pass any None to the Application
7683
# instance so default values will be generated for those fields
77-
if key in application_fields and value:
84+
if key in application_fields and (isinstance(value, bool) or value):
7885
if key == "user":
7986
application_data.update({"user_id": value})
8087
else:
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Generated by Django 4.2.5 on 2023-09-07 19:26
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
('oauth2_provider', '0008_alter_accesstoken_token'),
10+
]
11+
12+
operations = [
13+
migrations.AddField(
14+
model_name='application',
15+
name='hash_client_secret',
16+
field=models.BooleanField(default=True),
17+
),
18+
]

oauth2_provider/models.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@
2929
class ClientSecretField(models.CharField):
3030
def pre_save(self, model_instance, add):
3131
secret = getattr(model_instance, self.attname)
32+
should_be_hashed = getattr(model_instance, "hash_client_secret", True)
33+
if not should_be_hashed:
34+
return super().pre_save(model_instance, add)
35+
3236
try:
3337
hasher = identify_hasher(secret)
3438
logger.debug(f"{model_instance}: {self.attname} is already hashed with {hasher}.")
@@ -120,6 +124,7 @@ class AbstractApplication(models.Model):
120124
db_index=True,
121125
help_text=_("Hashed on Save. Copy it now if this is a new secret."),
122126
)
127+
hash_client_secret = models.BooleanField(default=True)
123128
name = models.CharField(max_length=255, blank=True)
124129
skip_authorization = models.BooleanField(default=False)
125130

0 commit comments

Comments
 (0)