We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Session timeout can be reduced
Currently the JWT Session Token currently has an excessive session timeout. The length of the timeout can be reduced to lower the risk of an attacker gaining access.

If a user leaves their computer unattended, a nearby attacker could access the user’s computer and any open applications. Automatically logging a user out after an extended period of inactivity can limit the time that an attacker could make use of any hijacked sessions.

References:
[OWASP's Session Management Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html)
[OWASP's Page on Session Timeout](https://owasp.org/www-community/Session_Timeout)

---

The referenced issue was found via a pen test conducted in collaboration with [Infor](https://www.infor.com/) and [Cobalt.io](https://www.cobalt.io/)

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `lemur/auth/service.py`
Content:
```
1 """
2 .. module: lemur.auth.service
3     :platform: Unix
4     :synopsis: This module contains all of the authentication duties for
5     lemur
6     :copyright: (c) 2018 by Netflix Inc., see AUTHORS for more
7     :license: Apache, see LICENSE for more details.
8 .. moduleauthor:: Kevin Glisson <kglisson@netflix.com>
9 
10 """
11 import jwt
12 import json
13 import binascii
14 
15 from functools import wraps
16 from datetime import datetime, timedelta
17 
18 from flask import g, current_app, jsonify, request
19 
20 from flask_restful import Resource
21 from flask_principal import identity_loaded, RoleNeed, UserNeed
22 
23 from flask_principal import Identity, identity_changed
24 
25 from cryptography.hazmat.backends import default_backend
26 from cryptography.hazmat.primitives import serialization
27 from cryptography.hazmat.primitives.asymmetric.rsa import RSAPublicNumbers
28 
29 from lemur.users import service as user_service
30 from lemur.api_keys import service as api_key_service
31 from lemur.auth.permissions import AuthorityCreatorNeed, RoleMemberNeed
32 
33 
34 def get_rsa_public_key(n, e):
35     """
36     Retrieve an RSA public key based on a module and exponent as provided by the JWKS format.
37 
38     :param n:
39     :param e:
40     :return: a RSA Public Key in PEM format
41     """
42     n = int(binascii.hexlify(jwt.utils.base64url_decode(bytes(n, "utf-8"))), 16)
43     e = int(binascii.hexlify(jwt.utils.base64url_decode(bytes(e, "utf-8"))), 16)
44 
45     pub = RSAPublicNumbers(e, n).public_key(default_backend())
46     return pub.public_bytes(
47         encoding=serialization.Encoding.PEM,
48         format=serialization.PublicFormat.SubjectPublicKeyInfo,
49     )
50 
51 
52 def create_token(user, aid=None, ttl=None):
53     """
54     Create a valid JWT for a given user/api key, this token is then used to authenticate
55     sessions until the token expires.
56 
57     :param user:
58     :return:
59     """
60     expiration_delta = timedelta(
61         days=int(current_app.config.get("LEMUR_TOKEN_EXPIRATION", 1))
62     )
63     payload = {"iat": datetime.utcnow(), "exp": datetime.utcnow() + expiration_delta}
64 
65     # Handle Just a User ID & User Object.
66     if isinstance(user, int):
67         payload["sub"] = user
68     else:
69         payload["sub"] = user.id
70     if aid is not None:
71         payload["aid"] = aid
72     # Custom TTLs are only supported on Access Keys.
73     if ttl is not None and aid is not None:
74         # Tokens that are forever until revoked.
75         if ttl == -1:
76             del payload["exp"]
77         else:
78             payload["exp"] = datetime.utcnow() + timedelta(days=ttl)
79     token = jwt.encode(payload, current_app.config["LEMUR_TOKEN_SECRET"])
80     return token
81 
82 
83 def login_required(f):
84     """
85     Validates the JWT and ensures that is has not expired and the user is still active.
86 
87     :param f:
88     :return:
89     """
90 
91     @wraps(f)
92     def decorated_function(*args, **kwargs):
93         if not request.headers.get("Authorization"):
94             response = jsonify(message="Missing authorization header")
95             response.status_code = 401
96             return response
97 
98         try:
99             token = request.headers.get("Authorization").split()[1]
100         except Exception as e:
101             return dict(message="Token is invalid"), 403
102 
103         try:
104             header_data = fetch_token_header(token)
105             payload = jwt.decode(token, current_app.config["LEMUR_TOKEN_SECRET"], algorithms=[header_data["alg"]])
106         except jwt.DecodeError:
107             return dict(message="Token is invalid"), 403
108         except jwt.ExpiredSignatureError:
109             return dict(message="Token has expired"), 403
110         except jwt.InvalidTokenError:
111             return dict(message="Token is invalid"), 403
112 
113         if "aid" in payload:
114             access_key = api_key_service.get(payload["aid"])
115             if access_key.revoked:
116                 return dict(message="Token has been revoked"), 403
117             if access_key.ttl != -1:
118                 current_time = datetime.utcnow()
119                 # API key uses days
120                 expired_time = datetime.fromtimestamp(access_key.issued_at) + timedelta(days=access_key.ttl)
121                 if current_time >= expired_time:
122                     return dict(message="Token has expired"), 403
123             if access_key.application_name:
124                 g.caller_application = access_key.application_name
125 
126         user = user_service.get(payload["sub"])
127 
128         if not user.active:
129             return dict(message="User is not currently active"), 403
130 
131         g.current_user = user
132 
133         if not g.current_user:
134             return dict(message="You are not logged in"), 403
135 
136         # Tell Flask-Principal the identity changed
137         identity_changed.send(
138             current_app._get_current_object(), identity=Identity(g.current_user.id)
139         )
140 
141         return f(*args, **kwargs)
142 
143     return decorated_function
144 
145 
146 def fetch_token_header(token):
147     """
148     Fetch the header out of the JWT token.
149 
150     :param token:
151     :return: :raise jwt.DecodeError:
152     """
153     token = token.encode("utf-8")
154     try:
155         signing_input, crypto_segment = token.rsplit(b".", 1)
156         header_segment, payload_segment = signing_input.split(b".", 1)
157     except ValueError:
158         raise jwt.DecodeError("Not enough segments")
159 
160     try:
161         return json.loads(jwt.utils.base64url_decode(header_segment).decode("utf-8"))
162     except TypeError as e:
163         current_app.logger.exception(e)
164         raise jwt.DecodeError("Invalid header padding")
165 
166 
167 @identity_loaded.connect
168 def on_identity_loaded(sender, identity):
169     """
170     Sets the identity of a given option, assigns additional permissions based on
171     the role that the user is a part of.
172 
173     :param sender:
174     :param identity:
175     """
176     # load the user
177     user = user_service.get(identity.id)
178 
179     # add the UserNeed to the identity
180     identity.provides.add(UserNeed(identity.id))
181 
182     # identity with the roles that the user provides
183     if hasattr(user, "roles"):
184         for role in user.roles:
185             identity.provides.add(RoleNeed(role.name))
186             identity.provides.add(RoleMemberNeed(role.id))
187 
188     # apply ownership for authorities
189     if hasattr(user, "authorities"):
190         for authority in user.authorities:
191             identity.provides.add(AuthorityCreatorNeed(authority.id))
192 
193     g.user = user
194 
195 
196 class AuthenticatedResource(Resource):
197     """
198     Inherited by all resources that need to be protected by authentication.
199     """
200 
201     method_decorators = [login_required]
202 
203     def __init__(self):
204         super(AuthenticatedResource, self).__init__()
205
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/lemur/auth/service.py b/lemur/auth/service.py
--- a/lemur/auth/service.py
+++ b/lemur/auth/service.py
@@ -8,27 +8,23 @@
 .. moduleauthor:: Kevin Glisson <kglisson@netflix.com>
 
 """
-import jwt
 import json
-import binascii
-
-from functools import wraps
 from datetime import datetime, timedelta
+from functools import wraps
 
-from flask import g, current_app, jsonify, request
-
-from flask_restful import Resource
-from flask_principal import identity_loaded, RoleNeed, UserNeed
-
-from flask_principal import Identity, identity_changed
-
+import binascii
+import jwt
 from cryptography.hazmat.backends import default_backend
 from cryptography.hazmat.primitives import serialization
 from cryptography.hazmat.primitives.asymmetric.rsa import RSAPublicNumbers
+from flask import g, current_app, jsonify, request
+from flask_principal import Identity, identity_changed
+from flask_principal import identity_loaded, RoleNeed, UserNeed
+from flask_restful import Resource
 
-from lemur.users import service as user_service
 from lemur.api_keys import service as api_key_service
 from lemur.auth.permissions import AuthorityCreatorNeed, RoleMemberNeed
+from lemur.users import service as user_service
 
 
 def get_rsa_public_key(n, e):
@@ -57,9 +53,21 @@
     :param user:
     :return:
     """
-    expiration_delta = timedelta(
-        days=int(current_app.config.get("LEMUR_TOKEN_EXPIRATION", 1))
-    )
+    expiration_delta = timedelta(days=1)
+    custom_expiry = current_app.config.get("LEMUR_TOKEN_EXPIRATION")
+    if custom_expiry:
+        if isinstance(custom_expiry, str) and custom_expiry.endswith("m"):
+            expiration_delta = timedelta(
+                minutes=int(custom_expiry.rstrip("m"))
+            )
+        elif isinstance(custom_expiry, str) and custom_expiry.endswith("h"):
+            expiration_delta = timedelta(
+                hours=int(custom_expiry.rstrip("h"))
+            )
+        else:
+            expiration_delta = timedelta(
+                days=int(custom_expiry)
+            )
     payload = {"iat": datetime.utcnow(), "exp": datetime.utcnow() + expiration_delta}
 
     # Handle Just a User ID & User Object.

{"golden_diff": "diff --git a/lemur/auth/service.py b/lemur/auth/service.py\n--- a/lemur/auth/service.py\n+++ b/lemur/auth/service.py\n@@ -8,27 +8,23 @@\n .. moduleauthor:: Kevin Glisson <kglisson@netflix.com>\n \n \"\"\"\n-import jwt\n import json\n-import binascii\n-\n-from functools import wraps\n from datetime import datetime, timedelta\n+from functools import wraps\n \n-from flask import g, current_app, jsonify, request\n-\n-from flask_restful import Resource\n-from flask_principal import identity_loaded, RoleNeed, UserNeed\n-\n-from flask_principal import Identity, identity_changed\n-\n+import binascii\n+import jwt\n from cryptography.hazmat.backends import default_backend\n from cryptography.hazmat.primitives import serialization\n from cryptography.hazmat.primitives.asymmetric.rsa import RSAPublicNumbers\n+from flask import g, current_app, jsonify, request\n+from flask_principal import Identity, identity_changed\n+from flask_principal import identity_loaded, RoleNeed, UserNeed\n+from flask_restful import Resource\n \n-from lemur.users import service as user_service\n from lemur.api_keys import service as api_key_service\n from lemur.auth.permissions import AuthorityCreatorNeed, RoleMemberNeed\n+from lemur.users import service as user_service\n \n \n def get_rsa_public_key(n, e):\n@@ -57,9 +53,21 @@\n     :param user:\n     :return:\n     \"\"\"\n-    expiration_delta = timedelta(\n-        days=int(current_app.config.get(\"LEMUR_TOKEN_EXPIRATION\", 1))\n-    )\n+    expiration_delta = timedelta(days=1)\n+    custom_expiry = current_app.config.get(\"LEMUR_TOKEN_EXPIRATION\")\n+    if custom_expiry:\n+        if isinstance(custom_expiry, str) and custom_expiry.endswith(\"m\"):\n+            expiration_delta = timedelta(\n+                minutes=int(custom_expiry.rstrip(\"m\"))\n+            )\n+        elif isinstance(custom_expiry, str) and custom_expiry.endswith(\"h\"):\n+            expiration_delta = timedelta(\n+                hours=int(custom_expiry.rstrip(\"h\"))\n+            )\n+        else:\n+            expiration_delta = timedelta(\n+                days=int(custom_expiry)\n+            )\n     payload = {\"iat\": datetime.utcnow(), \"exp\": datetime.utcnow() + expiration_delta}\n \n     # Handle Just a User ID & User Object.\n", "issue": "Session timeout can be reduced\nCurrently the JWT Session Token currently has an excessive session timeout. The length of the timeout can be reduced to lower the risk of an attacker gaining access.\r\n\r\nIf a user leaves their computer unattended, a nearby attacker could access the user\u2019s computer and any open applications. Automatically logging a user out after an extended period of inactivity can limit the time that an attacker could make use of any hijacked sessions.\r\n\r\nReferences:\r\n[OWASP's Session Management Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html)\r\n[OWASP's Page on Session Timeout](https://owasp.org/www-community/Session_Timeout)\r\n\r\n---\r\n\r\nThe referenced issue was found via a pen test conducted in collaboration with [Infor](https://www.infor.com/) and [Cobalt.io](https://www.cobalt.io/)\n", "before_files": [{"content": "\"\"\"\n.. module: lemur.auth.service\n    :platform: Unix\n    :synopsis: This module contains all of the authentication duties for\n    lemur\n    :copyright: (c) 2018 by Netflix Inc., see AUTHORS for more\n    :license: Apache, see LICENSE for more details.\n.. moduleauthor:: Kevin Glisson <kglisson@netflix.com>\n\n\"\"\"\nimport jwt\nimport json\nimport binascii\n\nfrom functools import wraps\nfrom datetime import datetime, timedelta\n\nfrom flask import g, current_app, jsonify, request\n\nfrom flask_restful import Resource\nfrom flask_principal import identity_loaded, RoleNeed, UserNeed\n\nfrom flask_principal import Identity, identity_changed\n\nfrom cryptography.hazmat.backends import default_backend\nfrom cryptography.hazmat.primitives import serialization\nfrom cryptography.hazmat.primitives.asymmetric.rsa import RSAPublicNumbers\n\nfrom lemur.users import service as user_service\nfrom lemur.api_keys import service as api_key_service\nfrom lemur.auth.permissions import AuthorityCreatorNeed, RoleMemberNeed\n\n\ndef get_rsa_public_key(n, e):\n    \"\"\"\n    Retrieve an RSA public key based on a module and exponent as provided by the JWKS format.\n\n    :param n:\n    :param e:\n    :return: a RSA Public Key in PEM format\n    \"\"\"\n    n = int(binascii.hexlify(jwt.utils.base64url_decode(bytes(n, \"utf-8\"))), 16)\n    e = int(binascii.hexlify(jwt.utils.base64url_decode(bytes(e, \"utf-8\"))), 16)\n\n    pub = RSAPublicNumbers(e, n).public_key(default_backend())\n    return pub.public_bytes(\n        encoding=serialization.Encoding.PEM,\n        format=serialization.PublicFormat.SubjectPublicKeyInfo,\n    )\n\n\ndef create_token(user, aid=None, ttl=None):\n    \"\"\"\n    Create a valid JWT for a given user/api key, this token is then used to authenticate\n    sessions until the token expires.\n\n    :param user:\n    :return:\n    \"\"\"\n    expiration_delta = timedelta(\n        days=int(current_app.config.get(\"LEMUR_TOKEN_EXPIRATION\", 1))\n    )\n    payload = {\"iat\": datetime.utcnow(), \"exp\": datetime.utcnow() + expiration_delta}\n\n    # Handle Just a User ID & User Object.\n    if isinstance(user, int):\n        payload[\"sub\"] = user\n    else:\n        payload[\"sub\"] = user.id\n    if aid is not None:\n        payload[\"aid\"] = aid\n    # Custom TTLs are only supported on Access Keys.\n    if ttl is not None and aid is not None:\n        # Tokens that are forever until revoked.\n        if ttl == -1:\n            del payload[\"exp\"]\n        else:\n            payload[\"exp\"] = datetime.utcnow() + timedelta(days=ttl)\n    token = jwt.encode(payload, current_app.config[\"LEMUR_TOKEN_SECRET\"])\n    return token\n\n\ndef login_required(f):\n    \"\"\"\n    Validates the JWT and ensures that is has not expired and the user is still active.\n\n    :param f:\n    :return:\n    \"\"\"\n\n    @wraps(f)\n    def decorated_function(*args, **kwargs):\n        if not request.headers.get(\"Authorization\"):\n            response = jsonify(message=\"Missing authorization header\")\n            response.status_code = 401\n            return response\n\n        try:\n            token = request.headers.get(\"Authorization\").split()[1]\n        except Exception as e:\n            return dict(message=\"Token is invalid\"), 403\n\n        try:\n            header_data = fetch_token_header(token)\n            payload = jwt.decode(token, current_app.config[\"LEMUR_TOKEN_SECRET\"], algorithms=[header_data[\"alg\"]])\n        except jwt.DecodeError:\n            return dict(message=\"Token is invalid\"), 403\n        except jwt.ExpiredSignatureError:\n            return dict(message=\"Token has expired\"), 403\n        except jwt.InvalidTokenError:\n            return dict(message=\"Token is invalid\"), 403\n\n        if \"aid\" in payload:\n            access_key = api_key_service.get(payload[\"aid\"])\n            if access_key.revoked:\n                return dict(message=\"Token has been revoked\"), 403\n            if access_key.ttl != -1:\n                current_time = datetime.utcnow()\n                # API key uses days\n                expired_time = datetime.fromtimestamp(access_key.issued_at) + timedelta(days=access_key.ttl)\n                if current_time >= expired_time:\n                    return dict(message=\"Token has expired\"), 403\n            if access_key.application_name:\n                g.caller_application = access_key.application_name\n\n        user = user_service.get(payload[\"sub\"])\n\n        if not user.active:\n            return dict(message=\"User is not currently active\"), 403\n\n        g.current_user = user\n\n        if not g.current_user:\n            return dict(message=\"You are not logged in\"), 403\n\n        # Tell Flask-Principal the identity changed\n        identity_changed.send(\n            current_app._get_current_object(), identity=Identity(g.current_user.id)\n        )\n\n        return f(*args, **kwargs)\n\n    return decorated_function\n\n\ndef fetch_token_header(token):\n    \"\"\"\n    Fetch the header out of the JWT token.\n\n    :param token:\n    :return: :raise jwt.DecodeError:\n    \"\"\"\n    token = token.encode(\"utf-8\")\n    try:\n        signing_input, crypto_segment = token.rsplit(b\".\", 1)\n        header_segment, payload_segment = signing_input.split(b\".\", 1)\n    except ValueError:\n        raise jwt.DecodeError(\"Not enough segments\")\n\n    try:\n        return json.loads(jwt.utils.base64url_decode(header_segment).decode(\"utf-8\"))\n    except TypeError as e:\n        current_app.logger.exception(e)\n        raise jwt.DecodeError(\"Invalid header padding\")\n\n\n@identity_loaded.connect\ndef on_identity_loaded(sender, identity):\n    \"\"\"\n    Sets the identity of a given option, assigns additional permissions based on\n    the role that the user is a part of.\n\n    :param sender:\n    :param identity:\n    \"\"\"\n    # load the user\n    user = user_service.get(identity.id)\n\n    # add the UserNeed to the identity\n    identity.provides.add(UserNeed(identity.id))\n\n    # identity with the roles that the user provides\n    if hasattr(user, \"roles\"):\n        for role in user.roles:\n            identity.provides.add(RoleNeed(role.name))\n            identity.provides.add(RoleMemberNeed(role.id))\n\n    # apply ownership for authorities\n    if hasattr(user, \"authorities\"):\n        for authority in user.authorities:\n            identity.provides.add(AuthorityCreatorNeed(authority.id))\n\n    g.user = user\n\n\nclass AuthenticatedResource(Resource):\n    \"\"\"\n    Inherited by all resources that need to be protected by authentication.\n    \"\"\"\n\n    method_decorators = [login_required]\n\n    def __init__(self):\n        super(AuthenticatedResource, self).__init__()\n", "path": "lemur/auth/service.py"}], "after_files": [{"content": "\"\"\"\n.. module: lemur.auth.service\n    :platform: Unix\n    :synopsis: This module contains all of the authentication duties for\n    lemur\n    :copyright: (c) 2018 by Netflix Inc., see AUTHORS for more\n    :license: Apache, see LICENSE for more details.\n.. moduleauthor:: Kevin Glisson <kglisson@netflix.com>\n\n\"\"\"\nimport json\nfrom datetime import datetime, timedelta\nfrom functools import wraps\n\nimport binascii\nimport jwt\nfrom cryptography.hazmat.backends import default_backend\nfrom cryptography.hazmat.primitives import serialization\nfrom cryptography.hazmat.primitives.asymmetric.rsa import RSAPublicNumbers\nfrom flask import g, current_app, jsonify, request\nfrom flask_principal import Identity, identity_changed\nfrom flask_principal import identity_loaded, RoleNeed, UserNeed\nfrom flask_restful import Resource\n\nfrom lemur.api_keys import service as api_key_service\nfrom lemur.auth.permissions import AuthorityCreatorNeed, RoleMemberNeed\nfrom lemur.users import service as user_service\n\n\ndef get_rsa_public_key(n, e):\n    \"\"\"\n    Retrieve an RSA public key based on a module and exponent as provided by the JWKS format.\n\n    :param n:\n    :param e:\n    :return: a RSA Public Key in PEM format\n    \"\"\"\n    n = int(binascii.hexlify(jwt.utils.base64url_decode(bytes(n, \"utf-8\"))), 16)\n    e = int(binascii.hexlify(jwt.utils.base64url_decode(bytes(e, \"utf-8\"))), 16)\n\n    pub = RSAPublicNumbers(e, n).public_key(default_backend())\n    return pub.public_bytes(\n        encoding=serialization.Encoding.PEM,\n        format=serialization.PublicFormat.SubjectPublicKeyInfo,\n    )\n\n\ndef create_token(user, aid=None, ttl=None):\n    \"\"\"\n    Create a valid JWT for a given user/api key, this token is then used to authenticate\n    sessions until the token expires.\n\n    :param user:\n    :return:\n    \"\"\"\n    expiration_delta = timedelta(days=1)\n    custom_expiry = current_app.config.get(\"LEMUR_TOKEN_EXPIRATION\")\n    if custom_expiry:\n        if isinstance(custom_expiry, str) and custom_expiry.endswith(\"m\"):\n            expiration_delta = timedelta(\n                minutes=int(custom_expiry.rstrip(\"m\"))\n            )\n        elif isinstance(custom_expiry, str) and custom_expiry.endswith(\"h\"):\n            expiration_delta = timedelta(\n                hours=int(custom_expiry.rstrip(\"h\"))\n            )\n        else:\n            expiration_delta = timedelta(\n                days=int(custom_expiry)\n            )\n    payload = {\"iat\": datetime.utcnow(), \"exp\": datetime.utcnow() + expiration_delta}\n\n    # Handle Just a User ID & User Object.\n    if isinstance(user, int):\n        payload[\"sub\"] = user\n    else:\n        payload[\"sub\"] = user.id\n    if aid is not None:\n        payload[\"aid\"] = aid\n    # Custom TTLs are only supported on Access Keys.\n    if ttl is not None and aid is not None:\n        # Tokens that are forever until revoked.\n        if ttl == -1:\n            del payload[\"exp\"]\n        else:\n            payload[\"exp\"] = datetime.utcnow() + timedelta(days=ttl)\n    token = jwt.encode(payload, current_app.config[\"LEMUR_TOKEN_SECRET\"])\n    return token\n\n\ndef login_required(f):\n    \"\"\"\n    Validates the JWT and ensures that is has not expired and the user is still active.\n\n    :param f:\n    :return:\n    \"\"\"\n\n    @wraps(f)\n    def decorated_function(*args, **kwargs):\n        if not request.headers.get(\"Authorization\"):\n            response = jsonify(message=\"Missing authorization header\")\n            response.status_code = 401\n            return response\n\n        try:\n            token = request.headers.get(\"Authorization\").split()[1]\n        except Exception as e:\n            return dict(message=\"Token is invalid\"), 403\n\n        try:\n            header_data = fetch_token_header(token)\n            payload = jwt.decode(token, current_app.config[\"LEMUR_TOKEN_SECRET\"], algorithms=[header_data[\"alg\"]])\n        except jwt.DecodeError:\n            return dict(message=\"Token is invalid\"), 403\n        except jwt.ExpiredSignatureError:\n            return dict(message=\"Token has expired\"), 403\n        except jwt.InvalidTokenError:\n            return dict(message=\"Token is invalid\"), 403\n\n        if \"aid\" in payload:\n            access_key = api_key_service.get(payload[\"aid\"])\n            if access_key.revoked:\n                return dict(message=\"Token has been revoked\"), 403\n            if access_key.ttl != -1:\n                current_time = datetime.utcnow()\n                # API key uses days\n                expired_time = datetime.fromtimestamp(access_key.issued_at) + timedelta(days=access_key.ttl)\n                if current_time >= expired_time:\n                    return dict(message=\"Token has expired\"), 403\n            if access_key.application_name:\n                g.caller_application = access_key.application_name\n\n        user = user_service.get(payload[\"sub\"])\n\n        if not user.active:\n            return dict(message=\"User is not currently active\"), 403\n\n        g.current_user = user\n\n        if not g.current_user:\n            return dict(message=\"You are not logged in\"), 403\n\n        # Tell Flask-Principal the identity changed\n        identity_changed.send(\n            current_app._get_current_object(), identity=Identity(g.current_user.id)\n        )\n\n        return f(*args, **kwargs)\n\n    return decorated_function\n\n\ndef fetch_token_header(token):\n    \"\"\"\n    Fetch the header out of the JWT token.\n\n    :param token:\n    :return: :raise jwt.DecodeError:\n    \"\"\"\n    token = token.encode(\"utf-8\")\n    try:\n        signing_input, crypto_segment = token.rsplit(b\".\", 1)\n        header_segment, payload_segment = signing_input.split(b\".\", 1)\n    except ValueError:\n        raise jwt.DecodeError(\"Not enough segments\")\n\n    try:\n        return json.loads(jwt.utils.base64url_decode(header_segment).decode(\"utf-8\"))\n    except TypeError as e:\n        current_app.logger.exception(e)\n        raise jwt.DecodeError(\"Invalid header padding\")\n\n\n@identity_loaded.connect\ndef on_identity_loaded(sender, identity):\n    \"\"\"\n    Sets the identity of a given option, assigns additional permissions based on\n    the role that the user is a part of.\n\n    :param sender:\n    :param identity:\n    \"\"\"\n    # load the user\n    user = user_service.get(identity.id)\n\n    # add the UserNeed to the identity\n    identity.provides.add(UserNeed(identity.id))\n\n    # identity with the roles that the user provides\n    if hasattr(user, \"roles\"):\n        for role in user.roles:\n            identity.provides.add(RoleNeed(role.name))\n            identity.provides.add(RoleMemberNeed(role.id))\n\n    # apply ownership for authorities\n    if hasattr(user, \"authorities\"):\n        for authority in user.authorities:\n            identity.provides.add(AuthorityCreatorNeed(authority.id))\n\n    g.user = user\n\n\nclass AuthenticatedResource(Resource):\n    \"\"\"\n    Inherited by all resources that need to be protected by authentication.\n    \"\"\"\n\n    method_decorators = [login_required]\n\n    def __init__(self):\n        super(AuthenticatedResource, self).__init__()\n", "path": "lemur/auth/service.py"}]}