Skip to content
This repository was archived by the owner on Apr 26, 2025. It is now read-only.

Commit e2c275e

Browse files
committed
Prevent 401 error to be raised when token is expired and auth is optional in FastAPI and Flask integration
1 parent 93d1f93 commit e2c275e

File tree

4 files changed

+43
-10
lines changed

4 files changed

+43
-10
lines changed

fief_client/integrations/fastapi.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,8 @@ async def _authenticated(
176176
else:
177177
info = result
178178
except (FiefAccessTokenInvalid, FiefAccessTokenExpired):
179+
if optional:
180+
return None
179181
return await self.get_unauthorized_response(request, response)
180182
except (FiefAccessTokenMissingScope, FiefAccessTokenMissingPermission):
181183
return await self.get_forbidden_response(request, response)

fief_client/integrations/flask.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,9 @@ def decorated_function(*args, **kwargs):
206206
token, required_scope=scope, required_permissions=permissions
207207
)
208208
except (FiefAccessTokenInvalid, FiefAccessTokenExpired) as e:
209+
if optional:
210+
g.access_token_info = None
211+
return f(*args, **kwargs)
209212
raise FiefAuthUnauthorized() from e
210213
except (
211214
FiefAccessTokenMissingScope,

tests/test_integrations_fastapi.py

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -180,17 +180,24 @@ async def test_optional(
180180
self, test_client: httpx.AsyncClient, generate_access_token, user_id: str
181181
):
182182
response = await test_client.get("/authenticated-optional")
183+
assert response.status_code == status.HTTP_200_OK
184+
assert response.json() is None
183185

186+
expired_access_token = generate_access_token(
187+
encrypt=False, scope="openid", exp=0
188+
)
189+
response = await test_client.get(
190+
"/authenticated-optional",
191+
headers={"Authorization": f"Bearer {expired_access_token}"},
192+
)
184193
assert response.status_code == status.HTTP_200_OK
185194
assert response.json() is None
186195

187196
access_token = generate_access_token(encrypt=False, scope="openid")
188-
189197
response = await test_client.get(
190198
"/authenticated-optional",
191199
headers={"Authorization": f"Bearer {access_token}"},
192200
)
193-
194201
assert response.status_code == status.HTTP_200_OK
195202
assert response.json() == {
196203
"id": user_id,
@@ -334,17 +341,24 @@ async def test_optional(
334341
)
335342

336343
response = await test_client.get("/current-user-optional")
344+
assert response.status_code == status.HTTP_200_OK
345+
assert response.json() is None
337346

347+
expired_access_token = generate_access_token(
348+
encrypt=False, scope="openid", exp=0
349+
)
350+
response = await test_client.get(
351+
"/current-user-optional",
352+
headers={"Authorization": f"Bearer {expired_access_token}"},
353+
)
338354
assert response.status_code == status.HTTP_200_OK
339355
assert response.json() is None
340356

341357
access_token = generate_access_token(encrypt=False, scope="openid")
342-
343358
response = await test_client.get(
344359
"/current-user-optional",
345360
headers={"Authorization": f"Bearer {access_token}"},
346361
)
347-
348362
assert response.status_code == status.HTTP_200_OK
349363
assert response.json() == {"sub": user_id}
350364

tests/test_integrations_flask.py

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -147,15 +147,22 @@ def test_optional(
147147
assert response.status_code == 200
148148
assert response.json == {}
149149

150-
access_token = generate_access_token(encrypt=False, scope="openid")
150+
expired_access_token = generate_access_token(
151+
encrypt=False, scope="openid", exp=0
152+
)
153+
response = test_client.get(
154+
"/authenticated-optional",
155+
headers={"Authorization": f"Bearer {expired_access_token}"},
156+
)
157+
assert response.status_code == 200
158+
assert response.json == {}
151159

160+
access_token = generate_access_token(encrypt=False, scope="openid")
152161
response = test_client.get(
153162
"/authenticated-optional",
154163
headers={"Authorization": f"Bearer {access_token}"},
155164
)
156-
157165
assert response.status_code == 200
158-
159166
assert response.json == {
160167
"id": user_id,
161168
"scope": ["openid"],
@@ -299,15 +306,22 @@ def test_optional(
299306
assert response.status_code == 200
300307
assert response.json == {}
301308

302-
access_token = generate_access_token(encrypt=False, scope="openid")
309+
expired_access_token = generate_access_token(
310+
encrypt=False, scope="openid", exp=0
311+
)
312+
response = test_client.get(
313+
"/current-user-optional",
314+
headers={"Authorization": f"Bearer {expired_access_token}"},
315+
)
316+
assert response.status_code == 200
317+
assert response.json == {}
303318

319+
access_token = generate_access_token(encrypt=False, scope="openid")
304320
response = test_client.get(
305321
"/current-user-optional",
306322
headers={"Authorization": f"Bearer {access_token}"},
307323
)
308-
309324
assert response.status_code == 200
310-
311325
assert response.json == {"sub": user_id}
312326

313327
def test_missing_scope(self, test_client: FlaskClient, generate_access_token):

0 commit comments

Comments
 (0)