django-bolt 0.1.0__cp310-abi3-win_amd64.whl → 0.1.1__cp310-abi3-win_amd64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of django-bolt might be problematic. Click here for more details.

Files changed (56) hide show
  1. django_bolt/__init__.py +2 -2
  2. django_bolt/_core.pyd +0 -0
  3. django_bolt/_json.py +169 -0
  4. django_bolt/admin/static_routes.py +15 -21
  5. django_bolt/api.py +181 -61
  6. django_bolt/auth/__init__.py +2 -2
  7. django_bolt/decorators.py +15 -3
  8. django_bolt/dependencies.py +30 -24
  9. django_bolt/error_handlers.py +2 -1
  10. django_bolt/openapi/plugins.py +3 -2
  11. django_bolt/openapi/schema_generator.py +65 -20
  12. django_bolt/pagination.py +2 -1
  13. django_bolt/responses.py +3 -2
  14. django_bolt/serialization.py +5 -4
  15. {django_bolt-0.1.0.dist-info → django_bolt-0.1.1.dist-info}/METADATA +179 -197
  16. {django_bolt-0.1.0.dist-info → django_bolt-0.1.1.dist-info}/RECORD +18 -55
  17. django_bolt/auth/README.md +0 -464
  18. django_bolt/auth/REVOCATION_EXAMPLE.md +0 -391
  19. django_bolt/tests/__init__.py +0 -0
  20. django_bolt/tests/admin_tests/__init__.py +0 -1
  21. django_bolt/tests/admin_tests/conftest.py +0 -6
  22. django_bolt/tests/admin_tests/test_admin_with_django.py +0 -278
  23. django_bolt/tests/admin_tests/urls.py +0 -9
  24. django_bolt/tests/cbv/__init__.py +0 -0
  25. django_bolt/tests/cbv/test_class_views.py +0 -570
  26. django_bolt/tests/cbv/test_class_views_django_orm.py +0 -703
  27. django_bolt/tests/cbv/test_class_views_features.py +0 -1173
  28. django_bolt/tests/cbv/test_class_views_with_client.py +0 -622
  29. django_bolt/tests/conftest.py +0 -165
  30. django_bolt/tests/test_action_decorator.py +0 -399
  31. django_bolt/tests/test_auth_secret_key.py +0 -83
  32. django_bolt/tests/test_decorator_syntax.py +0 -159
  33. django_bolt/tests/test_error_handling.py +0 -481
  34. django_bolt/tests/test_file_response.py +0 -192
  35. django_bolt/tests/test_global_cors.py +0 -172
  36. django_bolt/tests/test_guards_auth.py +0 -441
  37. django_bolt/tests/test_guards_integration.py +0 -303
  38. django_bolt/tests/test_health.py +0 -283
  39. django_bolt/tests/test_integration_validation.py +0 -400
  40. django_bolt/tests/test_json_validation.py +0 -536
  41. django_bolt/tests/test_jwt_auth.py +0 -327
  42. django_bolt/tests/test_jwt_token.py +0 -458
  43. django_bolt/tests/test_logging.py +0 -837
  44. django_bolt/tests/test_logging_merge.py +0 -419
  45. django_bolt/tests/test_middleware.py +0 -492
  46. django_bolt/tests/test_middleware_server.py +0 -230
  47. django_bolt/tests/test_model_viewset.py +0 -323
  48. django_bolt/tests/test_models.py +0 -24
  49. django_bolt/tests/test_pagination.py +0 -1258
  50. django_bolt/tests/test_parameter_validation.py +0 -178
  51. django_bolt/tests/test_syntax.py +0 -626
  52. django_bolt/tests/test_testing_utilities.py +0 -163
  53. django_bolt/tests/test_testing_utilities_simple.py +0 -123
  54. django_bolt/tests/test_viewset_unified.py +0 -346
  55. {django_bolt-0.1.0.dist-info → django_bolt-0.1.1.dist-info}/WHEEL +0 -0
  56. {django_bolt-0.1.0.dist-info → django_bolt-0.1.1.dist-info}/entry_points.txt +0 -0
@@ -1,20 +1,19 @@
1
- django_bolt-0.1.0.dist-info/METADATA,sha256=3Mfr4jMEEumR7ssfUB3v0tBJ-t8UNOfO7F_Z1tM8-2k,21102
2
- django_bolt-0.1.0.dist-info/WHEEL,sha256=4EDp_7DiFfWl1yYv5M4wSosAn5L_xgD1dyrQxQxfCx8,95
3
- django_bolt-0.1.0.dist-info/entry_points.txt,sha256=cUEGAdiOY6BryNhsgOS_50AONPPHajI3yvhqr56ZiaU,51
4
- django_bolt/__init__.py,sha256=SOWp15QP7uIZBC-gcbbxu4oGICTgZlteyH0liMEaGZc,3051
5
- django_bolt/_core.pyd,sha256=2f7Emz055G-jShl2Tl6BZ2ONNtlj7kLg5HS14o32PYY,8875520
1
+ django_bolt-0.1.1.dist-info/METADATA,sha256=h0ifCk91UOPGcMEaReodmlr2UBdueXw40w4HVUgEA94,21343
2
+ django_bolt-0.1.1.dist-info/WHEEL,sha256=4EDp_7DiFfWl1yYv5M4wSosAn5L_xgD1dyrQxQxfCx8,95
3
+ django_bolt-0.1.1.dist-info/entry_points.txt,sha256=cUEGAdiOY6BryNhsgOS_50AONPPHajI3yvhqr56ZiaU,51
4
+ django_bolt/__init__.py,sha256=fhXQUJR5SO-GwhF_2N9w0UK6rIFx7kWGfpOPyIKvB9Q,3139
5
+ django_bolt/_core.pyd,sha256=iMY9GY4G-NVQHoAtoIHjpukLVrjiqsZZPym6uYGILus,8905728
6
+ django_bolt/_json.py,sha256=oGxi29DHB8UYvbqjtqtrP6gThk7Qonlw333c4_cTr6s,4917
6
7
  django_bolt/admin/__init__.py,sha256=BNN1afSvWvt-377rNzZLdNDEvKyMZXkmB_0MhTxAN8k,601
7
8
  django_bolt/admin/admin_detection.py,sha256=1yQkLx9rF5DLMjJqbx8n4c82UgS9JEAnUcPdRfFqAXk,5825
8
9
  django_bolt/admin/asgi_bridge.py,sha256=oJrOqbBi8w-OUZD_wvpa5FlRFGIOyRvV284z8OS1kiY,9030
9
10
  django_bolt/admin/routes.py,sha256=dGrSz6fOwofLuBpNpzyqtcLuGbd4AgSQ2jZub_3cz1Y,3235
10
11
  django_bolt/admin/static.py,sha256=eXeOs2VWnxKdLDKarI4eD2q92K9R3JJHW1XQYmAsVDA,4692
11
- django_bolt/admin/static_routes.py,sha256=U12cU2Vpk_6dppAF2o4JDWG2s_Lk73kkCnSBJ5yuQAQ,3810
12
- django_bolt/api.py,sha256=fAw_SG6SyVgAEmvMpIWN30wE20k6vUgywKDx7bfpcnA,45901
12
+ django_bolt/admin/static_routes.py,sha256=sdpuCPhULMr5LccVxfbU2XSfpmL8oP7DCXqUpy0cnNY,3512
13
+ django_bolt/api.py,sha256=1wJOg4-fuDzhG9ovHXjA6ONqlEFEvfrjx97xpja4oBU,49386
13
14
  django_bolt/apps.py,sha256=OKBK6McSzRZ8zGQaId5iw239QbIgqs8tIbAqpuYxmn0,193
14
15
  django_bolt/async_collector.py,sha256=m1U6wjE9wheVMuql8aooR47tkLz_RlADgkIl2p9H6Uw,7749
15
- django_bolt/auth/README.md,sha256=YOOuGtq8Ss-WRGh2ODqzFxM252GsEB28LDZedBKn2u0,16582
16
- django_bolt/auth/REVOCATION_EXAMPLE.md,sha256=5gGUt7cMXuzEM4-24J8hZJe8OLZGLp6eN1A7QTSNdrs,11056
17
- django_bolt/auth/__init__.py,sha256=nIc_P5rXLjOkq3eFyzZ0B6vDmIGWlb-m1LsmF1LISos,1880
16
+ django_bolt/auth/__init__.py,sha256=ygi_SCzH1CNOcQwDe0ZKIe072xBa7zeKVUtUoG0_dwY,1968
18
17
  django_bolt/auth/backends.py,sha256=T02zfiC17GZrARKlqzKSnkMOtEcYQDTmS4PouRvsNOU,7944
19
18
  django_bolt/auth/guards.py,sha256=Dwbqhq4_I41BoN0eWrQ7Ad9mmr9zgCoPAg4C3GElTio,6591
20
19
  django_bolt/auth/jwt_utils.py,sha256=phLKyXQXrqL8TLLZVA-reitOVylSTJ9FKSBETa1_OCg,6518
@@ -24,9 +23,9 @@ django_bolt/binding.py,sha256=UtmwW55RKyBwNxbX5QQ74NF0EF5k5zaMGa5el7mgljg,12860
24
23
  django_bolt/bootstrap.py,sha256=zXkVhcDZxluQBWXc_UHK0FfgOfpdgxCg01DmSbSdXos,3007
25
24
  django_bolt/cli.py,sha256=0TBGM37cCqKEew_QA26ru7KkR8_6mP5wKXgFhr8GWng,4647
26
25
  django_bolt/compression.py,sha256=8ioDa2j0TG_mna-Jh34-e6WjCeY0GSKwRPHMn8en8OQ,4025
27
- django_bolt/decorators.py,sha256=oe1ZVuBhPadpHJv7CO0fTRvjeB_giIqxuVyTscW5u0I,6188
28
- django_bolt/dependencies.py,sha256=Vv72NT6CfBc6B6qEzAHN25qN9xUj7rJp6h-fDvEjERg,4146
29
- django_bolt/error_handlers.py,sha256=VYBJ0a5hbV6AhBvqycmiK6HLlPbxHkTBzzUpTqvyB6E,10018
26
+ django_bolt/decorators.py,sha256=hvfIZMxZI3S4eo6KYiOiEC-1Z96fSwQxQopLB4jmez0,6656
27
+ django_bolt/dependencies.py,sha256=D_D9onQLMH85q0o4tSeKo0nTiJmx_Hifg3AwwcTfRUM,4443
28
+ django_bolt/error_handlers.py,sha256=uD9_9vnub8FxZCRXgcqOdMic5M8cFD-sPXePdSl9IaY,10032
30
29
  django_bolt/exceptions.py,sha256=iYTkmtel7VlpjwuOrijDgt8fsx8_Kd0gezLEdR6CrDs,8823
31
30
  django_bolt/health.py,sha256=MBcXlgkTAdEiAvmGRPSgn9iePhH-rcHXan7Ge1EaPog,3356
32
31
  django_bolt/logging/__init__.py,sha256=bI71S22rJoMLtGg-ejh6qrlwDaW_lSV0ufxNbDw3NRQ,230
@@ -40,9 +39,9 @@ django_bolt/middleware/compiler.py,sha256=Knxh3XouU70ymIskDB-JWn1TcHSMPQvUBXtTPH
40
39
  django_bolt/middleware/middleware.py,sha256=Qdr16OM15oOS1OYNnxFY3hJ0un9E8VaVwht-A8Qcuws,8113
41
40
  django_bolt/openapi/__init__.py,sha256=LgvKbDBCGGKBvm6vW0nSmagtXw1CZ2swZf_ElhXIn68,572
42
41
  django_bolt/openapi/config.py,sha256=PHqd2LkSUZWpssj7hQHnUhgqKzaARjgKWyPdfEMlxvs,6230
43
- django_bolt/openapi/plugins.py,sha256=jKFx6jcpd9-gS7uWCY7v_PX68I-pRwT_lQ7iBs2AX94,15306
42
+ django_bolt/openapi/plugins.py,sha256=ncoxieMFzP4YAO4_gaNomcOBd6HZ0z3N-5TBU1d2ZTs,15348
44
43
  django_bolt/openapi/routes.py,sha256=08Tn1EA5wjvzJzks7v4oHI5qyrbU9-5KLLkfuij7JfI,6047
45
- django_bolt/openapi/schema_generator.py,sha256=j7wWW37MSibsBbo0XlfzQ966H7lw4z_l6wBVY7w5HUs,20468
44
+ django_bolt/openapi/schema_generator.py,sha256=JtTOccrSXjwcaMPMAftqjPQbzjEmr16kG0OOuaTuEJA,22237
46
45
  django_bolt/openapi/spec/__init__.py,sha256=a1ZJNgdoXKZSKOnxThuwhhDYqTBGSlUJU4JElfjtZY0,1759
47
46
  django_bolt/openapi/spec/base.py,sha256=qXTjQiKSllTDSTNTvXnxkyYXG4vQZnZU5Ev4jQfyfec,2418
48
47
  django_bolt/openapi/spec/callback.py,sha256=mvz71QTtYWQZQheWSsrvyssi3lb-vH7Diqj9Cf71ezg,937
@@ -76,53 +75,17 @@ django_bolt/openapi/spec/server.py,sha256=wvo84Z7WbV5s8glor5N5ywwM-B7C6YUqS_il0Q
76
75
  django_bolt/openapi/spec/server_variable.py,sha256=ZEqqp1FWOMARl2YIWrRXtX7AuwnuX5WtlN_63eQ5Jk0,1182
77
76
  django_bolt/openapi/spec/tag.py,sha256=uxn6IpNMDaTUdziQNVOMoZq4uAOGGSR1b5DbTcLvm8Y,913
78
77
  django_bolt/openapi/spec/xml.py,sha256=WfuYpX_eROu5bmGTeR5x6dK0T0nw6RIJP9Hc-nQBNZ4,1725
79
- django_bolt/pagination.py,sha256=3CfcWl3VgTAH0lyz0fbajV3lYzYS3coBjHCjiQeaLpU,22459
78
+ django_bolt/pagination.py,sha256=SUEgNxK4BWLTdNiegJeFoAWSxCAI1au8PO0IYGlGq5Q,22473
80
79
  django_bolt/param_functions.py,sha256=GIdm4ti7D40iVzj496ICq9Iu8TPeGVXNCJsODcTs4nE,1120
81
80
  django_bolt/params.py,sha256=_7N3_oa0mWuCuh1LKuaBDUS6TIeYWD_wVFrMJ-1L8Yg,8371
82
81
  django_bolt/request_parsing.py,sha256=7ZHfD7FkTJYsFSrEsFqmFW7JlC4m-0fAaTx089GXpf4,4818
83
- django_bolt/responses.py,sha256=_7SmTteQ-Tdgz020zWItX4b3JGys2NUfHCKVIK800wk,7231
82
+ django_bolt/responses.py,sha256=B0LXHN431c1-o93DC_xTF-wrnv8CMxn-1Sd0Yi4cwjE,7238
84
83
  django_bolt/router.py,sha256=wTFsPasg5Sh5hgdFp1kCmUrK6ugwRPWEj7PsxWOc9lc,1532
85
- django_bolt/serialization.py,sha256=S08Yq_H2YtEU9c7O7VZ4tkDv6BiOUobQQX_Ervh70pY,8832
84
+ django_bolt/serialization.py,sha256=Uza6jzQPTFxTQHnXEWBEDYY-3xDOGZinBSRE0T4KK28,8825
86
85
  django_bolt/status_codes.py,sha256=jTZ32kPwj3tC23jh6uC1Ci1P9EKttywsvyWINQIEwGg,9386
87
86
  django_bolt/testing/__init__.py,sha256=5UDYTmdyKkkY5ENlOlZcK0twbsLSylpjlp7oFgqNC-0,257
88
87
  django_bolt/testing/client.py,sha256=X1DXulzJHuN3RKvyMhEP4yhymc2UrUDBrnngho-m1yA,10008
89
88
  django_bolt/testing/helpers.py,sha256=Vv-4KuIbOVfCWQvohKpO37u59uhrhpWnRU5bWzbK5rg,2820
90
- django_bolt/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
91
- django_bolt/tests/admin_tests/__init__.py,sha256=7n1EF-XwQVo-2VQXFt-W8EosL8l6w6LOJ5Ff3Jkpo_Q,25
92
- django_bolt/tests/admin_tests/conftest.py,sha256=i8Og6NWC2c-i0p2zuXyeaKzRSZYvntaEJO51OMLdVew,172
93
- django_bolt/tests/admin_tests/test_admin_with_django.py,sha256=BuRaHpZ_Xt8aHhllhK4XIGsl8_oJxqTslgQ4Bm2Kdbc,9320
94
- django_bolt/tests/admin_tests/urls.py,sha256=gF111ic0YAEE_2_BEI0LKwmnacVqp4sft955AoH_XXg,182
95
- django_bolt/tests/cbv/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
96
- django_bolt/tests/cbv/test_class_views.py,sha256=uYx_UHxS2Dxno7MJnDQpXFY5fiJ-TGeaXkk42mXOX2s,16390
97
- django_bolt/tests/cbv/test_class_views_django_orm.py,sha256=bl_j2fB4IP35BIBPAzvkcfRuHOUFrt61rE3PKG1CpzE,23553
98
- django_bolt/tests/cbv/test_class_views_features.py,sha256=ub3wmlXnYSF0CUeFMkzr-Tg22lkPIK-BkWtaIV1oqHU,45032
99
- django_bolt/tests/cbv/test_class_views_with_client.py,sha256=_S3Qkw3T2RhF0Eme4xKQ7HpG1j9goylD9drF2Xotzbg,19410
100
- django_bolt/tests/conftest.py,sha256=RtuDXQy5tU6FJ_QydNe4rKok2dbXHOIolf4p4iCFqYc,5557
101
- django_bolt/tests/test_action_decorator.py,sha256=3mhv6Y2MisnoxTM0Fcy0Eqvlsn4ucRnFOwB6bK2bKQc,13002
102
- django_bolt/tests/test_auth_secret_key.py,sha256=GZzqCYmr8O20cBELttK59vUgRGsy1TDjHXsCPspz-cw,2915
103
- django_bolt/tests/test_decorator_syntax.py,sha256=LtcINgNxs8dIP1Ryl7lTwaxH7u8-BQRCdjCk0DJZg1A,4512
104
- django_bolt/tests/test_error_handling.py,sha256=RI0CEz02jSoH6wUZ-xNs2X0M8MROOyqhfx2SoAY3UC8,18260
105
- django_bolt/tests/test_file_response.py,sha256=ydBfSPk5YvblWArPiI24gSMuJtJR4kmdClNNs-_Ltxg,6190
106
- django_bolt/tests/test_global_cors.py,sha256=sf51Lj50Xklzy6-EXMOlF40VGYszTD34V17W3ypmAog,6451
107
- django_bolt/tests/test_guards_auth.py,sha256=bLwVCjfJBemgd8ksO7Su1efdVLOvX7bdZI7VMEN-WCs,15202
108
- django_bolt/tests/test_guards_integration.py,sha256=PFXNt3zwZH5PH3IeCiLr8dNSrjFTJw_M7kPvavqhJ_Y,10744
109
- django_bolt/tests/test_health.py,sha256=IgGfkizK-20hIFi56PygjcLtkQToxWZ6aI683-dQVn8,9092
110
- django_bolt/tests/test_integration_validation.py,sha256=QkHJuHliWzDmx7A3t6Lkr-ONuWDYv1uScs2DHIowp8E,14013
111
- django_bolt/tests/test_json_validation.py,sha256=zTQCZMTnzMiFTABDD0XhjU0uYYmmNoNZbtEjr_VnwdU,19615
112
- django_bolt/tests/test_jwt_auth.py,sha256=F3poh-a9uGKYLi4rGgtCYc92nLbDrxjst-Vl15gKN5s,9851
113
- django_bolt/tests/test_jwt_token.py,sha256=iOaa9_iZofSrv952lQfRyyNnkhmLx_bwSowYPIu2--A,15735
114
- django_bolt/tests/test_logging.py,sha256=zpzx3GP8G0o7jbwXMy6_CvF9c86SOvaQa05nDdytNEw,35751
115
- django_bolt/tests/test_logging_merge.py,sha256=sGELEpWWhVBP5HXKTJjtVX7CF6ZzUeAlrcr6tWJLcGY,16226
116
- django_bolt/tests/test_middleware.py,sha256=kIqcICLNSA5S8-mnyH_hvzx3YutPtpYYl8RzsUu_888,17091
117
- django_bolt/tests/test_middleware_server.py,sha256=HoRrroK8a6iusAOwnsEE7nR0vzZO5kW830JGJ3NZyKg,7810
118
- django_bolt/tests/test_model_viewset.py,sha256=b7x60ftTMwdCPprsiztWpU6KwWcG0-Fn2LevlYcbETw,11061
119
- django_bolt/tests/test_models.py,sha256=BuKmNOb-BkwBry_vUOZF2jFABZ1uh-vi_O9EiQRurxk,717
120
- django_bolt/tests/test_pagination.py,sha256=7hueeu7e5k2ZiZ6fvFilYEUsxqM5NTTFM0Uay8UvYLQ,39823
121
- django_bolt/tests/test_parameter_validation.py,sha256=M2Nr-WNOuUhv91I0RYBzjtv3wkYJSsTAQSSV1CoSXg4,5538
122
- django_bolt/tests/test_syntax.py,sha256=IyyP9q0w-poVxUrSOk2tsEHl9nx1ERs25ugmgZqaY2o,22071
123
- django_bolt/tests/test_testing_utilities.py,sha256=39w47yO6lE_FYWWDnQP24T-fkftJL2mZclWi2ZTNUvw,4787
124
- django_bolt/tests/test_testing_utilities_simple.py,sha256=sBaLWG0pb_-pyVjG8_StkBxIWCWdzTsV5LRkkV53cLQ,4223
125
- django_bolt/tests/test_viewset_unified.py,sha256=G-yWkvr9byXPOJGuVQhWe7XpSGnffXoxOTguJTyy3ZY,12219
126
89
  django_bolt/typing.py,sha256=sGlFUUXY8EJbYWCgARgNGLZPu7SaxxohZaSx1SRLYaE,8686
127
90
  django_bolt/views.py,sha256=KewSpL6g-zZxXnEkwun6hueX3S_Eji-d2dawzoqe-GM,41715
128
- django_bolt-0.1.0.dist-info/RECORD,,
91
+ django_bolt-0.1.1.dist-info/RECORD,,
@@ -1,464 +0,0 @@
1
- # Django-Bolt Authentication System
2
-
3
- High-performance authentication and authorization system where **validation happens in Rust without the GIL**, achieving 60k+ RPS with JWT authentication.
4
-
5
- ## Architecture
6
-
7
- ```
8
- ┌─────────────────────────────────────────────────────────────────┐
9
- │ Python Layer (Configuration) │
10
- │ │
11
- │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
12
- │ │ JWTAuth │ │ APIKeyAuth │ │ Guards │ │
13
- │ │ │ │ │ │ │ │
14
- │ │ .to_metadata()│ │ .to_metadata()│ │ .to_metadata()│ │
15
- │ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ │
16
- │ │ │ │ │
17
- │ └──────────────────┴──────────────────┘ │
18
- │ │ │
19
- │ Compile to metadata │
20
- │ │ │
21
- └────────────────────────────┼─────────────────────────────────────┘
22
-
23
-
24
- ┌─────────────────────────────────────────────────────────────────┐
25
- │ Rust Layer (Validation - NO GIL) │
26
- │ │
27
- │ ┌──────────────────────────────────────────────────────────┐ │
28
- │ │ Route Registration │ │
29
- │ │ • Parse metadata → typed Rust enums │ │
30
- │ │ • Store auth backends & guards per route │ │
31
- │ └──────────────────────────────────────────────────────────┘ │
32
- │ │
33
- │ ┌──────────────────────────────────────────────────────────┐ │
34
- │ │ Request Processing (HOT PATH - NO GIL) │ │
35
- │ │ │ │
36
- │ │ 1. Extract token from header │ │
37
- │ │ 2. Validate JWT (jsonwebtoken crate) │ │
38
- │ │ 3. Check guards/permissions │ │
39
- │ │ 4. Populate request.context with auth data │ │
40
- │ │ │ │
41
- │ │ ⚡ All happens without touching Python/GIL │ │
42
- │ └──────────────────────────────────────────────────────────┘ │
43
- └─────────────────────────────────────────────────────────────────┘
44
-
45
-
46
- ┌─────────────────────────────────────────────────────────────────┐
47
- │ Python Handler (WITH AuthContext) │
48
- │ │
49
- │ async def my_handler(request): │
50
- │ user_id = request["context"]["user_id"] │
51
- │ is_admin = request["context"]["is_admin"] │
52
- │ permissions = request["context"]["permissions"] │
53
- │ claims = request["context"]["auth_claims"] │
54
- │ ... │
55
- └─────────────────────────────────────────────────────────────────┘
56
- ```
57
-
58
- ## Module Structure
59
-
60
- ```
61
- django_bolt/auth/
62
- ├── __init__.py # Public API exports
63
- ├── README.md # This file
64
- ├── backends.py # Authentication backends (JWT, API key, Session)
65
- ├── guards.py # Permission guards (IsAuthenticated, IsAdmin, etc.)
66
- ├── middleware.py # Middleware decorators (cors, rate_limit, etc.)
67
- └── token.py # JWT Token dataclass with encode/decode
68
- ```
69
-
70
- ## Quick Start
71
-
72
- ### 1. Define Authentication Backend
73
-
74
- ```python
75
- from django_bolt import BoltAPI, JWTAuthentication, IsAuthenticated, Token
76
- from datetime import timedelta
77
-
78
- api = BoltAPI()
79
-
80
- # Create JWT token for a user
81
- def create_token_for_user(user):
82
- return Token.create(
83
- sub=str(user.id),
84
- expires_delta=timedelta(hours=1),
85
- is_staff=user.is_staff,
86
- is_admin=user.is_superuser,
87
- permissions=list(user.get_all_permissions()),
88
- email=user.email,
89
- ).encode(secret=settings.SECRET_KEY)
90
-
91
- # Protected endpoint
92
- @api.get(
93
- "/profile",
94
- auth=[JWTAuthentication()],
95
- guards=[IsAuthenticated()]
96
- )
97
- async def get_profile(request):
98
- user_id = request["context"]["user_id"]
99
- is_admin = request["context"]["is_admin"]
100
-
101
- return {
102
- "user_id": user_id,
103
- "is_admin": is_admin,
104
- "permissions": request["context"].get("permissions", [])
105
- }
106
- ```
107
-
108
- ### 2. Global Authentication (Settings)
109
-
110
- ```python
111
- # settings.py
112
-
113
- BOLT_AUTHENTICATION_CLASSES = [
114
- JWTAuthentication(
115
- secret=SECRET_KEY,
116
- algorithms=["HS256"],
117
- header="authorization",
118
- audience="my-api",
119
- )
120
- ]
121
-
122
- BOLT_DEFAULT_PERMISSION_CLASSES = [
123
- IsAuthenticated()
124
- ]
125
- ```
126
-
127
- Now all routes are protected by default unless you override with `guards=[AllowAny()]`.
128
-
129
- ### 3. Per-Route Authentication Override
130
-
131
- ```python
132
- from django_bolt import APIKeyAuthentication, HasPermission
133
-
134
- # Admin-only endpoint with API key auth
135
- @api.delete(
136
- "/users/{user_id}",
137
- auth=[APIKeyAuthentication(api_keys={"admin-key-123"})],
138
- guards=[HasPermission("users.delete")]
139
- )
140
- async def delete_user(user_id: int):
141
- # Only callable with valid API key and users.delete permission
142
- return {"deleted": user_id}
143
- ```
144
-
145
- ## Authentication Backends
146
-
147
- ### JWTAuthentication
148
-
149
- High-performance JWT validation in Rust using the `jsonwebtoken` crate.
150
-
151
- ```python
152
- from django_bolt import JWTAuthentication
153
-
154
- auth = JWTAuthentication(
155
- secret="your-secret-key", # Default: Django SECRET_KEY
156
- algorithms=["HS256"], # Supported: HS256/384/512, RS256/384/512, ES256/384
157
- header="authorization", # Header to extract token from
158
- audience="my-api", # Optional: validate aud claim
159
- issuer="auth-service", # Optional: validate iss claim
160
- )
161
- ```
162
-
163
- **Token Format**: `Authorization: Bearer <jwt-token>`
164
-
165
- **Performance**: ~60k RPS with JWT validation
166
-
167
- ### APIKeyAuthentication
168
-
169
- Simple API key validation with optional per-key permissions.
170
-
171
- ```python
172
- from django_bolt import APIKeyAuthentication
173
-
174
- auth = APIKeyAuthentication(
175
- api_keys={"key1", "key2", "admin-key"},
176
- header="x-api-key",
177
- key_permissions={
178
- "admin-key": ["users.create", "users.delete", "posts.create"],
179
- "key1": ["users.view"],
180
- "key2": ["posts.view", "posts.create"],
181
- }
182
- )
183
- ```
184
-
185
- **Header Format**: `X-API-Key: your-api-key`
186
-
187
- ### SessionAuthentication
188
-
189
- Django session-based authentication (falls back to Python execution).
190
-
191
- ```python
192
- from django_bolt import SessionAuthentication
193
-
194
- auth = SessionAuthentication()
195
- ```
196
-
197
- **Note**: This has higher overhead than JWT/API key as it requires Python execution per request.
198
-
199
- ## Permission Guards
200
-
201
- Guards are checked **after authentication** in Rust, providing early 403 responses without GIL overhead.
202
-
203
- ### AllowAny
204
-
205
- Allow unauthenticated requests (bypasses global defaults).
206
-
207
- ```python
208
- from django_bolt import AllowAny
209
-
210
- @api.get("/public", guards=[AllowAny()])
211
- async def public_endpoint():
212
- return {"message": "Anyone can access this"}
213
- ```
214
-
215
- ### IsAuthenticated
216
-
217
- Require valid authentication (any backend).
218
-
219
- ```python
220
- from django_bolt import IsAuthenticated
221
-
222
- @api.get("/protected", guards=[IsAuthenticated()])
223
- async def protected():
224
- return {"message": "Must be authenticated"}
225
- ```
226
-
227
- ### IsAdminUser / IsStaff
228
-
229
- Require admin or staff status (from JWT claims `is_superuser`, `is_admin`, or `is_staff`).
230
-
231
- ```python
232
- from django_bolt import IsAdminUser, IsStaff
233
-
234
- @api.get("/admin", guards=[IsAdminUser()])
235
- async def admin_only():
236
- return {"message": "Admin access"}
237
-
238
- @api.get("/staff", guards=[IsStaff()])
239
- async def staff_only():
240
- return {"message": "Staff access"}
241
- ```
242
-
243
- ### HasPermission / HasAnyPermission / HasAllPermissions
244
-
245
- Fine-grained permission checking.
246
-
247
- ```python
248
- from django_bolt import HasPermission, HasAnyPermission, HasAllPermissions
249
-
250
- # Require specific permission
251
- @api.delete("/users/{id}", guards=[HasPermission("users.delete")])
252
- async def delete_user(id: int):
253
- pass
254
-
255
- # Require at least one permission
256
- @api.put("/users/{id}", guards=[HasAnyPermission("users.edit", "users.admin")])
257
- async def edit_user(id: int):
258
- pass
259
-
260
- # Require all permissions
261
- @api.post("/admin/reset", guards=[HasAllPermissions("admin.full", "admin.reset")])
262
- async def reset_system():
263
- pass
264
- ```
265
-
266
- ## JWT Token Class
267
-
268
- The `Token` dataclass provides a Pythonic interface for JWT tokens with validation.
269
-
270
- ### Creating Tokens
271
-
272
- ```python
273
- from django_bolt import Token
274
- from datetime import datetime, timedelta, timezone
275
-
276
- # Option 1: Direct instantiation
277
- token = Token(
278
- sub="user123",
279
- exp=datetime.now(timezone.utc) + timedelta(hours=1),
280
- is_staff=True,
281
- permissions=["read", "write"],
282
- )
283
-
284
- # Option 2: Factory method (recommended)
285
- token = Token.create(
286
- sub="user123",
287
- expires_delta=timedelta(hours=1),
288
- is_staff=True,
289
- is_admin=False,
290
- permissions=["users.view", "posts.create"],
291
- # Extra custom claims
292
- tenant_id="acme-corp",
293
- role="manager",
294
- )
295
-
296
- # Encode to JWT string
297
- jwt_string = token.encode(secret="my-secret", algorithm="HS256")
298
- ```
299
-
300
- ### Decoding Tokens
301
-
302
- ```python
303
- # Decode and validate
304
- token = Token.decode(
305
- jwt_string,
306
- secret="my-secret",
307
- algorithm="HS256",
308
- audience="my-api", # Optional
309
- issuer="auth-service", # Optional
310
- verify_exp=True, # Verify expiration
311
- verify_nbf=True, # Verify not-before
312
- )
313
-
314
- print(token.sub) # "user123"
315
- print(token.is_staff) # True
316
- print(token.permissions) # ["users.view", "posts.create"]
317
- print(token.extras) # {"tenant_id": "acme-corp", "role": "manager"}
318
- ```
319
-
320
- ### Integration with Django Users
321
-
322
- ```python
323
- from django_bolt.jwt_utils import create_jwt_for_user
324
-
325
- # Create token from Django User instance
326
- user = await User.objects.aget(username="john")
327
- token = create_jwt_for_user(
328
- user,
329
- expires_in=3600, # 1 hour
330
- extra_claims={
331
- "permissions": ["users.view", "posts.create"],
332
- "tenant": "acme",
333
- }
334
- )
335
-
336
- # Use in login endpoint
337
- @api.post("/login")
338
- async def login(username: str, password: str):
339
- # Authenticate user...
340
- token = create_jwt_for_user(user)
341
- return {"access_token": token, "token_type": "bearer"}
342
- ```
343
-
344
- ## Request Context
345
-
346
- After authentication, the request context is populated with auth data:
347
-
348
- ```python
349
- @api.get("/me")
350
- async def get_current_user_info(request):
351
- ctx = request["context"]
352
-
353
- # Always available after successful auth
354
- user_id = ctx["user_id"] # str: User identifier
355
- is_staff = ctx["is_staff"] # bool: Staff status
356
- is_admin = ctx["is_admin"] # bool: Admin status
357
- backend = ctx["auth_backend"] # str: "jwt", "api_key", etc.
358
-
359
- # Available if permissions configured
360
- permissions = ctx.get("permissions", []) # list[str]: Permission strings
361
-
362
- # Available for JWT auth
363
- if "auth_claims" in ctx:
364
- claims = ctx["auth_claims"]
365
- exp = claims["exp"] # Expiration timestamp
366
- iat = claims["iat"] # Issued at timestamp
367
- # Plus any custom claims
368
-
369
- return {"user_id": user_id, "is_admin": is_admin}
370
- ```
371
-
372
- ### Helper Functions
373
-
374
- ```python
375
- from django_bolt.jwt_utils import (
376
- get_current_user, # Fetch Django User from DB
377
- extract_user_id_from_context,
378
- get_auth_context,
379
- )
380
- from django_bolt.params import Depends
381
-
382
- # Dependency injection to get Django User
383
- @api.get("/profile")
384
- async def my_profile(user=Depends(get_current_user)):
385
- if not user:
386
- return {"error": "Not authenticated"}
387
-
388
- return {
389
- "id": user.id,
390
- "username": user.username,
391
- "email": user.email,
392
- }
393
-
394
- # Extract just the user ID
395
- @api.get("/data")
396
- async def get_data(request):
397
- user_id = extract_user_id_from_context(request)
398
- # Use user_id...
399
- ```
400
-
401
- ## Performance Characteristics
402
-
403
- | Operation | Performance | Notes |
404
- |-----------|-------------|-------|
405
- | JWT Validation | ~60k+ RPS | Entirely in Rust, no GIL |
406
- | API Key Check | ~65k+ RPS | Simple HashSet lookup |
407
- | Guard Check | ~65k+ RPS | In-memory permission check |
408
- | Session Auth | ~10-15k RPS | Falls back to Python/Django |
409
-
410
- **Key Insight**: Authentication/authorization happens in the hot path **before** calling Python handlers, so most invalid requests are rejected at ~60k RPS without ever touching the GIL.
411
-
412
- ## Rust Implementation Details
413
-
414
- ### Key Files
415
-
416
- - **`src/middleware/auth.rs`**: JWT/API key validation, Claims struct, AuthContext
417
- - **`src/metadata.rs`**: Parse Python metadata → Rust types at registration
418
- - **`src/permissions.rs`**: Guard enum and validation logic
419
- - **`src/lib.rs`**: Request processing pipeline
420
-
421
- ### Performance Optimizations
422
-
423
- 1. **Zero-copy validation**: JWT validation uses `jsonwebtoken` crate directly on request bytes
424
- 2. **No GIL during auth**: Entire auth pipeline runs without acquiring GIL
425
- 3. **Early rejection**: Invalid tokens/permissions rejected before Python handler call
426
- 4. **Metadata compilation**: Auth config parsed once at registration, not per-request
427
- 5. **Efficient data structures**: DashMap for rate limiting, HashSet for permissions
428
-
429
- ## Testing
430
-
431
- ```bash
432
- # Run auth tests
433
- uv run pytest python/django_bolt/tests/test_guards_auth.py -v
434
- uv run pytest python/django_bolt/tests/test_jwt_token.py -v
435
-
436
- # All tests
437
- uv run pytest python/django_bolt/tests/ -v
438
- ```
439
-
440
- ## Migration from Old Code
441
-
442
- If you had direct imports from `django_bolt.auth` or `django_bolt.permissions`, they still work:
443
-
444
- ```python
445
- # Old imports (still work via backward compat shim)
446
- from django_bolt.auth import JWTAuthentication
447
- from django_bolt.permissions import IsAuthenticated
448
-
449
- # New organized imports (recommended)
450
- from django_bolt.auth import JWTAuthentication, IsAuthenticated
451
- # or
452
- from django_bolt import JWTAuthentication, IsAuthenticated
453
- ```
454
-
455
- ## Examples
456
-
457
- See `/python/examples/testproject/testproject/api.py` for real-world usage examples.
458
-
459
- ## Benchmarks
460
-
461
- ```bash
462
- # Run auth-specific benchmarks
463
- make bench-auth # TODO: Add auth benchmarks to Makefile
464
- ```