Created
December 22, 2023 12:59
-
-
Save AksAman/8cbb9c80f320a2aac98faa61661cdec4 to your computer and use it in GitHub Desktop.
Verify Next Auth JWT on python based backends
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import json | |
| import os | |
| import time | |
| from typing import Any | |
| from Crypto.Protocol.KDF import HKDF # pip install pycryptodome cryptography | |
| from Crypto.Hash import SHA256 | |
| from jose import jwe # pip install python-jose | |
| from dataclasses import dataclass, field | |
| DEFAULT_NEXT_AUTH_CONTEXT = "NextAuth.js Generated Encryption Key" | |
| @dataclass | |
| class NextAuthVerifier: | |
| next_auth_secret: str | None = field( | |
| default_factory=lambda: os.getenv("NEXTAUTH_SECRET") | |
| ) | |
| context: str = field(default=str.encode(DEFAULT_NEXT_AUTH_CONTEXT)) | |
| key_len: int = field(default=32) | |
| def __get_derived_key__(self) -> bytes: | |
| # Think about including the context in your environment variables. | |
| return HKDF( | |
| master=self.next_auth_secret.encode(), | |
| key_len=self.key_len, | |
| salt="".encode(), | |
| hashmod=SHA256, | |
| num_keys=1, | |
| context=self.context, | |
| ) | |
| def decrypt(self, token: str) -> dict[str, Any] | None: | |
| try: | |
| key = self.__get_derived_key__() | |
| raw_payload = jwe.decrypt(jwe_str=token, key=key).decode() | |
| return json.loads(raw_payload) | |
| except Exception as e: | |
| # can replace this with your own error handling | |
| print(e) | |
| return None | |
| def is_expired(self, payload: dict[str, Any]) -> bool: | |
| exp = payload.get("exp") | |
| if not exp: | |
| raise ValueError("exp not found in payload") | |
| return time.time() > exp | |
| # usage | |
| if __name__ == "__main__": | |
| decrypter = NextAuthVerifier(secret=os.getenv("NEXTAUTH_SECRET")) | |
| token = "eyJhbGciOiJkaXIiLsadadsOiJBMjU2R0NNIn0...." # can be from request.headers["Authorization"] | |
| payload = decrypter.decrypt(token=token) | |
| print(payload) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment