mirror of
https://github.com/tiennm99/DocsGPT.git
synced 2026-10-17 00:14:24 +00:00
feat(pat): authenticate personal access tokens
handle_auth resolves a dgpt_pat_ bearer against the database instead of decoding it as a JWT, for both the Flask and the ASGI routes. Scopes and the resource filter always come from the token row, and the claims that mark a PAT are stripped from decoded JWTs so a session token cannot pose as one. ASGI routes reject tokens unless they name the scope that admits them, and /api/user/me reports what the calling token may do.
This commit is contained in:
1 parent
22ecc0aee3
commit
174130607a
8 files changed
+604
-3
No files matched your search
@@ -4,7 +4,28 @@ from jose.exceptions import ExpiredSignatureError
|
||||
from docsgpt.core.settings import settings
|
||||
|
||||
|
||||
# Claims only the PAT verifier may set. Dropped from decoded JWTs so a session
|
||||
# token can never present itself as a (differently scoped) personal access token.
|
||||
_PAT_ONLY_CLAIMS = ("auth_method", "pat_id", "pat_name", "scopes", "resource_filter")
|
||||
|
||||
|
||||
def _bearer_value(request):
|
||||
header = request.headers.get("Authorization")
|
||||
if not header or not isinstance(header, str):
|
||||
return None
|
||||
scheme, _, value = header.partition(" ")
|
||||
return value.strip() if scheme.lower() == "bearer" and value else header.strip()
|
||||
|
||||
|
||||
def handle_auth(request, data={}):
|
||||
# Personal access tokens are opaque (not JWTs) and resolve against the
|
||||
# database in every auth mode that supports them, including AUTH_TYPE unset.
|
||||
from docsgpt.api.pat.tokens import authenticate_pat, looks_like_pat
|
||||
|
||||
bearer = _bearer_value(request)
|
||||
if looks_like_pat(bearer):
|
||||
return authenticate_pat(bearer, request)
|
||||
|
||||
if settings.AUTH_TYPE in ["simple_jwt", "session_jwt", "oidc"]:
|
||||
jwt_token = request.headers.get("Authorization")
|
||||
if not jwt_token:
|
||||
@@ -26,6 +47,8 @@ def handle_auth(request, data={}):
|
||||
# requirement is scoped to oidc.
|
||||
options={"verify_exp": is_oidc, "require_exp": is_oidc},
|
||||
)
|
||||
for claim in _PAT_ONLY_CLAIMS:
|
||||
decoded_token.pop(claim, None)
|
||||
return decoded_token
|
||||
except ExpiredSignatureError:
|
||||
return {
|
||||
|
||||
Reference in new issue
Block a user