67 lines
2.2 KiB
Python
67 lines
2.2 KiB
Python
"""
|
|
MIT License
|
|
|
|
Copyright (c) 2025 Hopsenn
|
|
|
|
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.
|
|
"""
|
|
|
|
import requests
|
|
|
|
from jose import jwt, JWTError
|
|
from . import settings
|
|
|
|
|
|
|
|
def verify_id_token(id_token, access_token):
|
|
"""
|
|
Verifies the given ID token using the JWKS from the HopID server.
|
|
Returns claims if valid, raises JWTError otherwise.
|
|
"""
|
|
|
|
jwks_url = f"{settings.HOPID_URL}/.well-known/jwks.json"
|
|
|
|
try:
|
|
jwks = requests.get(jwks_url, timeout=5).json()
|
|
|
|
unverified_header = jwt.get_unverified_header(id_token)
|
|
kid = unverified_header.get('kid')
|
|
|
|
if not kid:
|
|
raise JWTError("Missing 'kid' in ID token header")
|
|
|
|
key = next((k for k in jwks.get('keys', []) if k.get('kid') == kid), None)
|
|
if not key:
|
|
raise JWTError(f"No matching public key found for kid: {kid}")
|
|
|
|
claims = jwt.decode(
|
|
id_token,
|
|
key=key,
|
|
algorithms=["RS256"],
|
|
audience=settings.HOPID_CLIENT_ID,
|
|
issuer=settings.HOPID_URL.rstrip('/'),
|
|
access_token=access_token
|
|
)
|
|
|
|
return claims
|
|
|
|
except (requests.RequestException, KeyError, JWTError) as e:
|
|
print(f"ID token verification failed: {e}")
|
|
raise
|