Package: simplejwt-multisessions
simplejwt_multisessions is a Django app based ondjangorestframework-simplejwtthat allows you
to generate SIMPLE_JWT with two different lifetimes and session features.Introductionsimplejwt_multisessions is an MIT licensed Django app that allows Django devs to generate refresh
tokens with two different lifetimes i.e., “SHORT” and “LONG”. simplejwt_multisessions is designed
to manage tokens and sessions together. This app also can assign different policies to each type of lifetime category.Why use simplejwt_multisessions?Generates “LONG” and “SHORT” simpleJWT lifetime.Sets information of the session on the initialization. e.g., “Safari 15.6.1, iOS 15.6.1, iPhone”Extendable option for each session type with different policies.Extension of the session after each request by generating a new refresh token.Extension of the session once after each specific timedelta by generating a new refresh token.Limitable option for the available number of sessions. i.e., a User can log in as a “LONG” sessionwith only 3 different Endpoints/Devices or the User can log in as a “SHORT” session at the same
time with only 2 different Endpoints/Devices.
1. Sets max number of available sessions for each session type: “SHORT”, “LONG”.
2. Sets destroying oldest active sessions. i.e., if the user reaches the max number of active
sessions then by logging a new session the oldest session will be destroyed.Returns list of active i.e., not expired sessions assigned to requested user with itssession_id.Destroys sessions by theirsession_id.Destroys all other active/not expired sessions except the one making the request.Differentiable URLs for different APIs e.g., “login”, “refresh”, “list”, “destroy”, “destroyAllOther” and “logout”.Most of API’s permission_classes are set toAllowAnyand need to receivesecret_keyin the body of the requestwhich is defined in settings of simplejwt_multisessions in settings.py and the rest are set toIsAuthenticatedand need nothing else.RequirementsPython3.8+Django3.2+djangorestframework3.12+djangorestframework-simplejwt5.0.0+User guideInstallationInstall with pip:$python-mpipinstallsimplejwt_multisessionsClone the repo into your Django Projecthttps://github.com/benyaamin/simplejwt_multisessionssettings.py configurationTo start using simplejwt_multisessions, after installation of requirements first you should addrest_framework_simplejwt.token_blacklisttoINSTALLED_APPSinsettings.pyand then addsimplejwt_multisessionsto it.# Django Project settings.pyINSTALLED_APPS=[# ..."rest_framework_simplejwt.token_blacklist","simplejwt_multisessions",# ...]According to djangorestframework-simplejwt configuration instruction:https://django-rest-framework-simplejwt.readthedocs.io/en/latest/getting_started.html#project-configuration# Django Project settings.pyREST_FRAMEWORK={# ...'DEFAULT_AUTHENTICATION_CLASSES':(# ...'rest_framework_simplejwt.authentication.JWTAuthentication')# ...}You also need to add djangorestframework-simplejwt settings to settings.pyhttps://django-rest-framework-simplejwt.readthedocs.io/en/latest/settings.html#settings# Django project settings.pyfromdatetimeimporttimedelta#...SIMPLE_JWT={'ACCESS_TOKEN_LIFETIME':timedelta(minutes=5),'REFRESH_TOKEN_LIFETIME':timedelta(days=30),'ROTATE_REFRESH_TOKENS':False,'BLACKLIST_AFTER_ROTATION':False,'UPDATE_LAST_LOGIN':False,'ALGORITHM':'HS256','SIGNING_KEY':SECRET_KEY,'VERIFYING_KEY':None,'AUDIENCE':None,'ISSUER':None,'JWK_URL':None,'LEEWAY':0,'AUTH_HEADER_TYPES':('Bearer',),'AUTH_HEADER_NAME':'HTTP_AUTHORIZATION','USER_ID_FIELD':'id','USER_ID_CLAIM':'user_id','USER_AUTHENTICATION_RULE':'rest_framework_simplejwt.authentication.default_user_authentication_rule','AUTH_TOKEN_CLASSES':('rest_framework_simplejwt.tokens.AccessToken',),'TOKEN_TYPE_CLAIM':'token_type','TOKEN_USER_CLASS':'rest_framework_simplejwt.models.TokenUser','JTI_CLAIM':'jti','SLIDING_TOKEN_REFRESH_EXP_CLAIM':'refresh_exp','SLIDING_TOKEN_LIFETIME':timedelta(minutes=5),'SLIDING_TOKEN_REFRESH_LIFETIME':timedelta(days=1),}After adding SEIMPLE_JWT to your Django’s settings.py, Now you are good to add simplejwt_multisessions’s settings
tosettings.py# Django project settings.pyJWT_MULTISESSIONS={'SECRET':SECRET_KEY,'LONG_SESSION':{# This section is the "LONG_SESSION" configuration.'REFRESH_TOKEN_LIFETIME':SIMPLE_JWT['REFRESH_TOKEN_LIFETIME'],# or you can set the timedelta what you wish e.g., timedelta(days = 29)'ROTATE_REFRESH_TOKENS':False,# If set this flag true then after each token refresh request a new refresh token will be generated and the old one will be blacklisted'UPDATE_LAST_LOGIN':False,# By settings this flag to true after each request the session `lastUpdateDate` updates.'BLACKLIST_AFTER_ROTATION':False,'EXTEND_SESSION':True,# This flag specifies whether should extend the refresh lifetime after each refresh request or shouldn't'EXTEND_SESSION_EVERY_TIME':False,# If `EXTEND_SESSION` is set to true this flag specifies to extend refresh lifetime with the exact amount of `REFRESH_TOKEN_LIFETIME`'EXTEND_SESSION_ONCE_AFTER_EACH':timedelta(days=15),# If `EXTEND_SESSION` is set to true but `EXTEND_SESSION_EVERY_TIME` is set to False, then the refresh token will be extended as much as this property specifies.'LIMIT_NUMBER_OF_AVAIL_SESSIONS':True,# This feature decides to restrict the number of available sessions.'MAX_NUMBER_ACTIVE_SESSIONS':5,# If `LIMIT_NUMBER_OF_AVAIL_SESSIONS` is set to true then this property defines the max number of active sessions and prevents requests to exceed more than its value.'DESTROY_OLDEST_ACTIVE_SESSION':True,# If `LIMIT_NUMBER_OF_AVAIL_SESSIONS` is set to true by setting this flag to true and the max number of requests exceeds `MAX_NUMBER_ACTIVE_SESSIONS` then the newly arrived request will destroy the oldest session and the new session will be initialized.},'SHORT_SESSION':{# This section is the "SHORT_SESSION" configuration. The features are as same as what is mentioned in the `LONG_SESSION` section.'REFRESH_TOKEN_LIFETIME':timedelta(days=1),'ROTATE_REFRESH_TOKENS':False,'UPDATE_LAST_LOGIN':True,'BLACKLIST_AFTER_ROTATION':True,'EXTEND_SESSION':False,'EXTEND_SESSION_EVERY_TIME':False,'EXTEND_SESSION_ONCE_AFTER_EACH':timedelta(hours=12),'LIMIT_NUMBER_OF_AVAIL_SESSIONS':True,'MAX_NUMBER_ACTIVE_SESSIONS':2,'DESTROY_OLDEST_ACTIVE_SESSION':True,}}URLsIf you are intended to usesimplejwt_multisessionsyou should instead of using URLs related torest_framework_simplejwtuse the URLs mentioned below:# <root_of_your_django_project>/urls.py#...fromsimplejwt_multisessions.api.viewsimport(initializeSession,refreshSession,listOfActiveSessions,destroySessionById,destroyAllOtherSessions,logout,)#...urlpatterns=[...path('api/session/login/',initializeSession,name='initialize_session'),path('api/session/refresh/',refreshSession,name='refresh_session'),path('api/session/list/',listOfActiveSessions,name='list_sessions'),path('api/session/destroy/',destroySessionById,name='destroy_session_by_id'),path('api/session/destroyAllOther/',destroyAllOtherSessions,name="destroy_all_other"),path('api/session/logout/',logout,name='logout'),#...]UsageLogin and RefreshFor logging in or initializing a new session you need five variables to mention in your request’s body:username: The username_field of the Django user modelpassword: The password of the Django user modelsecret_key: The secret_key mentioned in JWT_MULTISESSIONS settings insettings.pysession: The session type of the request options: [“LONG”, “SHORT”]info: This field can store arbitrary information about the session. for instance Device id or browser version or IP address e.g., “Safari 15.6.1, iOS 15.6.1, iPhone”. NOTICE: This field is not changeable after initialization.curl \
    -X POST \
    -H "Content-Type: application/json" \
    -d '{"username": "benyamin", "password": "somepassword",
    "secret_key": "the_Secret_Key", "session": "LONG",
    "info": "sample info"}' \
    http://localhost:8000/api/session/login/

...
{
    "refresh": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTY2NTc1OTU2MywiaWF0IjoxNjYzMTY3NTYzLCJqdGkiOiJkOWFiYTMzYWNmMDg0ODU2YjJjMjA4OWJiYTFjZDc0YSIsInVzZXJfaWQiOjF9.zGwSDoJzoCEhIqwg3D4bRAwrnJ0DKRKSGOzdyyw__ho",
    "access": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNjYzMTY4MTYzLCJpYXQiOjE2NjMxNjc1NjMsImp0aSI6IjBlZGZlMmY3MzhiMzRhOWFhYzQ4ZDhjYzAxOTVmZjEzIiwidXNlcl9pZCI6MX0.QCEqyFmXk5-yHZ4dYKnhNx80o9mgAYRdgFfUtgV1lQQ",
    "session_id": "ozdyyw__ho-10"
}Same as classicsimpleJWTYou can use the returned access token to prove authentication for a protected view:curl \
-H "Authorization: JWT eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNjYzMTY4MTYzLCJpYXQiOjE2NjMxNjc1NjMsImp0aSI6IjBlZGZlMmY3MzhiMzRhOWFhYzQ4ZDhjYzAxOTVmZjEzIiwidXNlcl9pZCI6MX0.QCEqyFmXk5-yHZ4dYKnhNx80o9mgAYRdgFfUtgV1lQQ" \
http://localhost:8000/api/some-protected-view/When this access token expires, you can use the refresh token to obtain another access token:
NOTICE:
1. Since refresh API’spermission_classesisAllowAnyyou need to enter thesecret_keythat is assigned in simplejwt_multisessions’s settings insettings.py.
2. You should enter“session”in your request’s body. This“session”must be the same as the one you used in the login request otherwise the session will be destroyed.curl \
-X POST \
-H "Content-Type: application/json" \
-d '{"refresh":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTY2NTc1OTU2MywiaWF0IjoxNjYzMTY3NTYzLCJqdGkiOiJkOWFiYTMzYWNmMDg0ODU2YjJjMjA4OWJiYTFjZDc0YSIsInVzZXJfaWQiOjF9.zGwSDoJzoCEhIqwg3D4bRAwrnJ0DKRKSGOzdyyw__ho",
     "secret_key": "the_Secret_Key", "session": "LONG"}' \
http://localhost:8000/api/session/refresh/

...
{"access":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNjYzMTcwNTA5LCJpYXQiOjE2NjMxNjc1NjMsImp0aSI6IjQxNWMxNjcwMmVkNTRkYWM5MDk0OTkyMmExMjcyMTdjIiwidXNlcl9pZCI6MX0.gdSQUmoSt_-ir87xngbC7YIvwNsAXJaAy0l4IRfuT1I"}List of all sessionsTo see the list of user’s all active sessions you can use the list’s API.
You have to enter“session”in the body of your request.“session”can be one of these options:[“SHORT”, “LONG”, “ALL”]1. If you ask for“SHORT”sessions, in return you will just see the list of all short types of sessions and related info.
2. If you ask for“LONG”sessions, in return you will just see the list of all long types of sessions and related info.
3. If you ask for“ALL”sessions, in return you will see the list of all types of sessions and related info, and by“ALL”, it means“SHORT”and“LONG”sessions in total.
NOTICE: Since this API’spermission_classesis set toIsAuthenticatedthe proof of authentication is mandatory.“session”: “SHORT”curl \
-X POST \
-H "Content-Type: application/json" \
-H "Authorization: JWT eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNjYzMTY4MTYzLCJpYXQiOjE2NjMxNjc1NjMsImp0aSI6IjBlZGZlMmY3MzhiMzRhOWFhYzQ4ZDhjYzAxOTVmZjEzIiwidXNlcl9pZCI6MX0.QCEqyFmXk5-yHZ4dYKnhNx80o9mgAYRdgFfUtgV1lQQ" \
-d '{"session":"SHORT"}' \
http://localhost:8000/api/session/list/{
    "Short":
        {
            "Available Sessions":"0",
            "Sessions":[
                {
                    "session_id":"8e_ikeorsa-8",
                    "created_at":"2022-09-11T11:16:26Z",
                    "last_update":"2022-09-14T14:41:26Z",
                    "expires_at":"2022-09-15T14:41:26Z",
                    "session_info":"Safari 15.6.1, iOS 15.6.1, iPhone"
                },
                {
                    "session_id":"oetqjgyp1o-9",
                    "created_at":"2022-09-14T08:23:14Z",
                    "last_update":"2022-09-14T14:41:20Z",
                    "expires_at":"2022-09-15T14:41:20Z",
                    "session_info":"Chrome 105.0.0.0, OS X 10.15.7 64-bit"
                }
            ]
        }
}“session”: “LONG”curl \
-X POST \
-H "Content-Type: application/json" \
-H "Authorization: JWT eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNjYzMTY4MTYzLCJpYXQiOjE2NjMxNjc1NjMsImp0aSI6IjBlZGZlMmY3MzhiMzRhOWFhYzQ4ZDhjYzAxOTVmZjEzIiwidXNlcl9pZCI6MX0.QCEqyFmXk5-yHZ4dYKnhNx80o9mgAYRdgFfUtgV1lQQ" \
-d '{"session":"LONG"}' \
http://localhost:8000/api/session/list/{
    "Long":
        {
            "Available Sessions":"2",
            "Sessions":[
                {
                    "session_id": "8oeptkbkk0-3",
                    "created_at": "2022-09-08T19:14:33Z",
                    "last_update": "2022-09-08T19:14:33.108983Z",
                    "expires_at": "2022-10-08T19:14:33Z",
                    "session_info": "iOS native app, V1.0.2"
                },
                {
                    "session_id": "sppfiktswq-4",
                    "created_at": "2022-09-08T19:14:59Z",
                    "last_update": "2022-09-08T19:14:59.905518Z",
                    "expires_at": "2022-10-08T19:14:59Z",
                    "session_info": "android native app, V1.4"
                },
                {
                    "session_id": "rvu6qdlcdc-5",
                    "created_at": "2022-09-08T19:15:22Z",
                    "last_update": "2022-09-08T19:15:22.407307Z",
                    "expires_at": "2022-10-08T19:15:22Z",
                    "session_info": "react native app, V2.5"
                },
            ]
        }
}“session”: “ALL”curl \
-X POST \
-H "Content-Type: application/json" \
-H "Authorization: JWT eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNjYzMTY4MTYzLCJpYXQiOjE2NjMxNjc1NjMsImp0aSI6IjBlZGZlMmY3MzhiMzRhOWFhYzQ4ZDhjYzAxOTVmZjEzIiwidXNlcl9pZCI6MX0.QCEqyFmXk5-yHZ4dYKnhNx80o9mgAYRdgFfUtgV1lQQ" \
-d '{"session":"ALL"}' \
http://localhost:8000/api/session/list/{
    "Short":
        {
            "Available Sessions":"0",
            "Sessions":[
                {
                    "session_id":"8e_ikeorsa-8",
                    "created_at":"2022-09-11T11:16:26Z",
                    "last_update":"2022-09-14T14:41:26Z",
                    "expires_at":"2022-09-15T14:41:26Z",
                    "session_info":"Safari 15.6.1, iOS 15.6.1, iPhone"
                },
                {
                    "session_id":"oetqjgyp1o-9",
                    "created_at":"2022-09-14T08:23:14Z",
                    "last_update":"2022-09-14T14:41:20Z",
                    "expires_at":"2022-09-15T14:41:20Z",
                    "session_info":"Chrome 105.0.0.0, OS X 10.15.7 64-bit"
                }
            ]
        },
    "Long":
        {
            "Available Sessions":"2",
            "Sessions":[
                {
                    "session_id": "8oeptkbkk0-3",
                    "created_at": "2022-09-08T19:14:33Z",
                    "last_update": "2022-09-08T19:14:33.108983Z",
                    "expires_at": "2022-10-08T19:14:33Z",
                    "session_info": "iOS native app, V1.0.2"
                },
                {
                    "session_id": "sppfiktswq-4",
                    "created_at": "2022-09-08T19:14:59Z",
                    "last_update": "2022-09-08T19:14:59.905518Z",
                    "expires_at": "2022-10-08T19:14:59Z",
                    "session_info": "android native app, V1.4"
                },
                {
                    "session_id": "rvu6qdlcdc-5",
                    "created_at": "2022-09-08T19:15:22Z",
                    "last_update": "2022-09-08T19:15:22.407307Z",
                    "expires_at": "2022-10-08T19:15:22Z",
                    "session_info": "react native app, V2.5"
                },
            ]
        }
}Destroy session by their idSometimes End-User wants to terminate one of its active sessions. This action can be done by knowing the“session_id”and using‘destroy’’s API.
NOTICE: Since this API’spermission_classesis set toIsAuthenticatedthe proof of authentication is mandatory.curl \
-X POST \
-H "Content-Type: application/json" \
-H "Authorization: JWT eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNjYzMTY4MTYzLCJpYXQiOjE2NjMxNjc1NjMsImp0aSI6IjBlZGZlMmY3MzhiMzRhOWFhYzQ4ZDhjYzAxOTVmZjEzIiwidXNlcl9pZCI6MX0.QCEqyFmXk5-yHZ4dYKnhNx80o9mgAYRdgFfUtgV1lQQ" \
-d '{"session_id":"rvu6qdlcdc-5"}' \
http://localhost:8000/api/session/destroy/{}Destroy all other sessionsThis API allows the End-User to destroy all other active sessions except the one that makes the request.
Necessary inputs:[“session”, “refresh”].“session”specifies the session type to be destroyed.“refresh”specifies the considered“refresh”token assigned to the current request session and is excluded from being destroyed.
NOTICE: Since this API’spermission_classesis set toIsAuthenticatedthe proof of authentication is mandatory.“session”: “SHORT”curl \
-X POST \
-H "Content-Type: application/json" \
-H "Authorization: JWT eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNjYzMTY4MTYzLCJpYXQiOjE2NjMxNjc1NjMsImp0aSI6IjBlZGZlMmY3MzhiMzRhOWFhYzQ4ZDhjYzAxOTVmZjEzIiwidXNlcl9pZCI6MX0.QCEqyFmXk5-yHZ4dYKnhNx80o9mgAYRdgFfUtgV1lQQ" \
-d '{"session":"SHORT",
"refresh": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTY2NTc1OTU2MywiaWF0IjoxNjYzMTY3NTYzLCJqdGkiOiJkOWFiYTMzYWNmMDg0ODU2YjJjMjA4OWJiYTFjZDc0YSIsInVzZXJfaWQiOjF9.zGwSDoJzoCEhIqwg3D4bRAwrnJ0DKRKSGOzdyyw__ho"}' \
http://localhost:8000/api/session/destroyAllOther/{}“session”: “LONG”curl \
-X POST \
-H "Content-Type: application/json" \
-H "Authorization: JWT eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNjYzMTY4MTYzLCJpYXQiOjE2NjMxNjc1NjMsImp0aSI6IjBlZGZlMmY3MzhiMzRhOWFhYzQ4ZDhjYzAxOTVmZjEzIiwidXNlcl9pZCI6MX0.QCEqyFmXk5-yHZ4dYKnhNx80o9mgAYRdgFfUtgV1lQQ" \
-d '{"session":"LONG",
"refresh": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTY2NTc1OTU2MywiaWF0IjoxNjYzMTY3NTYzLCJqdGkiOiJkOWFiYTMzYWNmMDg0ODU2YjJjMjA4OWJiYTFjZDc0YSIsInVzZXJfaWQiOjF9.zGwSDoJzoCEhIqwg3D4bRAwrnJ0DKRKSGOzdyyw__ho"}' \
http://localhost:8000/api/session/destroyAllOther/{}“session”: “ALL”curl \
-X POST \
-H "Content-Type: application/json" \
-H "Authorization: JWT eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNjYzMTY4MTYzLCJpYXQiOjE2NjMxNjc1NjMsImp0aSI6IjBlZGZlMmY3MzhiMzRhOWFhYzQ4ZDhjYzAxOTVmZjEzIiwidXNlcl9pZCI6MX0.QCEqyFmXk5-yHZ4dYKnhNx80o9mgAYRdgFfUtgV1lQQ" \
-d '{"session":"ALL",
"refresh": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTY2NTc1OTU2MywiaWF0IjoxNjYzMTY3NTYzLCJqdGkiOiJkOWFiYTMzYWNmMDg0ODU2YjJjMjA4OWJiYTFjZDc0YSIsInVzZXJfaWQiOjF9.zGwSDoJzoCEhIqwg3D4bRAwrnJ0DKRKSGOzdyyw__ho"}' \
http://localhost:8000/api/session/destroyAllOther/{}LogoutThis API facilitates logging out the session.
Necessary inputs:[“secret_key”, “refresh”]. The secret_key mentioned in JWT_MULTISESSIONS settings in settings.py.“refresh”must be the refresh token the one that makes the request and is about to log out.curl \
-X POST \
-H "Content-Type: application/json" \
-d '{"secret_key": "the_Secret_Key",
"refresh": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTY2NTc1OTU2MywiaWF0IjoxNjYzMTY3NTYzLCJqdGkiOiJkOWFiYTMzYWNmMDg0ODU2YjJjMjA4OWJiYTFjZDc0YSIsInVzZXJfaWQiOjF9.zGwSDoJzoCEhIqwg3D4bRAwrnJ0DKRKSGOzdyyw__ho"}' \
http://localhost:8000/api/session/logout/{}LicenseThe licenses ofdjangorestframeworkanddjangorestframework-simplejwtprojects have been included in this repository in the “licenses” directory.MIT License

Copyright (c) 2022 Benyamin Agha Ebrahimi

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.