{"id":9288,"library":"sanic-jwt","title":"Sanic JWT","description":"Sanic-JWT provides a JWT (JSON Web Token) authentication flow for the Sanic web framework. It simplifies the process of user authentication, token generation, and securing endpoints. The library is currently at version 1.8.0, with releases focused on compatibility with newer Sanic and PyJWT versions, and feature enhancements.","status":"active","version":"1.8.0","language":"en","source_language":"en","source_url":"https://github.com/ahopkins/sanic-jwt","tags":["sanic","jwt","authentication","api","web"],"install":[{"cmd":"pip install sanic-jwt","lang":"bash","label":"Install stable version"}],"dependencies":[{"reason":"Core web framework for which sanic-jwt provides authentication services.","package":"sanic","optional":false},{"reason":"Handles the encoding and decoding of JSON Web Tokens.","package":"PyJWT","optional":false}],"imports":[{"symbol":"SanicJWT","correct":"from sanic_jwt import SanicJWT"},{"note":"The `protected` decorator was moved to the top-level package for direct import.","wrong":"from sanic_jwt.decorators import protected","symbol":"protected","correct":"from sanic_jwt import protected"},{"symbol":"Configuration","correct":"from sanic_jwt import Configuration"}],"quickstart":{"code":"from sanic import Sanic, response\nfrom sanic_jwt import SanicJWT, protected\nimport os\n\napp = Sanic(\"my_jwt_app\")\n\n# Set a secret key for JWT signing. Crucial for security.\napp.config.SANIC_JWT_SECRET = os.environ.get(\"SANIC_JWT_SECRET\", \"your-super-secret-key-that-no-one-knows\")\n\n# Define an asynchronous authentication function.\n# This function handles both token verification (payload present) and user login (payload None).\nasync def authenticate(request, payload):\n    if payload: # Token verification for protected routes\n        # In a real app, you'd fetch user data from a DB based on payload (e.g., user_id)\n        user_id = payload.get(\"user_id\")\n        if user_id:\n            return {\"user_id\": user_id, \"username\": payload.get(\"username\", \"user\")} # Return user info for ctx\n        return False\n    else: # User login attempt for the /auth endpoint\n        # Expect username/password in request.json\n        username = request.json.get(\"username\")\n        password = request.json.get(\"password\")\n\n        if username == \"test\" and password == \"test\": # Dummy check\n            return {\"user_id\": 1, \"username\": \"testuser\"} # Return user info to be included in JWT payload\n        return False # Authentication failed\n\n# Initialize Sanic-JWT with the app and your custom authentication function.\nSanicJWT.setup(app, authenticate=authenticate)\n\n@app.route(\"/protected\")\n@protected()\nasync def protected_route(request):\n    # Access user data via request.ctx.user after successful authentication\n    username = request.ctx.user.get('username', 'authenticated user')\n    return response.json({\"message\": f\"Hello, {username}! This is a protected route.\"})\n\n@app.get(\"/public\")\nasync def public_route(request):\n    return response.json({\"message\": \"This is a public route, accessible without a token.\"})\n\nif __name__ == \"__main__\":\n    # To run:\n    # 1. Start the app: python your_script_name.py\n    # 2. Login (obtain token): curl -X POST -H \"Content-Type: application/json\" -d '{\"username\":\"test\",\"password\":\"test\"}' http://localhost:8000/auth\n    # 3. Access protected route with token: curl -H \"Authorization: Bearer <your_token_here>\" http://localhost:8000/protected\n    app.run(host=\"0.0.0.0\", port=8000, debug=True)\n","lang":"python","description":"This quickstart demonstrates how to set up `sanic-jwt` with a Sanic application. It includes a simple authentication function, a protected route using the `@protected()` decorator, and a public route. Users obtain a JWT by POSTing to the `/auth` endpoint with credentials, and then use this token in the `Authorization: Bearer` header for protected routes."},"warnings":[{"fix":"Review PyJWT v2 documentation for API changes. Update any direct PyJWT calls in your code. Ensure secrets and tokens are handled as bytes or strings as required by PyJWT v2.","message":"Upgrading `sanic-jwt` to v1.6.0 or newer introduces PyJWT v2 support. If your application or custom JWT handling code directly interacts with PyJWT, you may encounter breaking changes related to API updates, especially regarding `jwt.encode()` parameters (e.g., `algorithm='none'` deprecation) and bytes vs string handling.","severity":"breaking","affected_versions":">=1.6.0"},{"fix":"Upgrade `sanic-jwt` to version 1.7.0 or newer to ensure compatibility with Sanic 21.3+.","message":"Versions of `sanic-jwt` prior to v1.7.0 may not be fully compatible with Sanic versions 21.3 and newer. This can lead to unexpected errors or authentication failures due to internal API changes in Sanic.","severity":"breaking","affected_versions":"<1.7.0 (when used with Sanic >=21.3)"},{"fix":"Replace `request.query_args` with `request.args` in your application code.","message":"The `request.query_args` attribute was deprecated and eventually removed from Sanic. Using it in your `authenticate` function or other custom logic will cause `AttributeError` on newer Sanic versions. `sanic-jwt` itself adjusted to use `request.args` in v1.3.1.","severity":"deprecated","affected_versions":"<1.3.1 (for sanic-jwt) or any version if using `request.query_args` directly"},{"fix":"Update client-side code to correctly handle HTTP 401 responses for invalid or missing tokens.","message":"Since `sanic-jwt` v1.2.0, requests with invalid tokens (e.g., malformed, expired, invalid signature) will return an HTTP 401 Unauthorized status code instead of 403 Forbidden. This might require adjustments to client-side error handling logic.","severity":"gotcha","affected_versions":">=1.2.0"}],"env_vars":null,"last_verified":"2026-04-16T00:00:00.000Z","next_check":"2026-07-15T00:00:00.000Z","problems":[{"fix":"Update your code to use `request.args` instead of `request.query_args`. Ensure your `sanic-jwt` version is 1.3.1 or newer.","cause":"Your custom authentication logic or an older version of sanic-jwt is attempting to access `request.query_args`, which has been removed in newer Sanic versions.","error":"AttributeError: 'Request' object has no attribute 'query_args'"},{"fix":"Verify that `app.config.SANIC_JWT_SECRET` in your Sanic application exactly matches the secret key used to sign the JWT. Check for typos or environment variable mismatches.","cause":"The JWT signature does not match the expected signature, likely due to a different secret key being used for signing than for verification, or the token being tampered with.","error":"jwt.exceptions.InvalidSignatureError: Signature verification failed"},{"fix":"Ensure your `SANIC_JWT_SECRET` is correctly formatted for the chosen algorithm. For symmetric algorithms (like HS256), a strong string or byte string is usually sufficient. For asymmetric (RSA, ECDSA), ensure you're providing correct private/public key pairs.","cause":"The secret key provided for JWT operations is not valid for the configured algorithm (e.g., using a simple string with an RSA algorithm, or incorrect key format).","error":"jwt.exceptions.InvalidKeyError: The specified key is not valid for the current algorithm"},{"fix":"Ensure `app.config.SANIC_JWT_SECRET` (and any other necessary `SANIC_JWT_` settings) are explicitly set to a non-`None` value before `SanicJWT.setup()` is called.","cause":"The `SANIC_JWT_SECRET` or other critical configuration settings for `sanic-jwt` are not properly defined or are `None`, leading to runtime errors when they are accessed.","error":"TypeError: 'NoneType' object has no attribute 'get' (or similar errors related to configuration)"}]}