{"id":14974213,"url":"https://github.com/bcgov/flask-jwt-oidc","last_synced_at":"2025-10-02T02:31:33.585Z","repository":{"id":65331074,"uuid":"589766865","full_name":"bcgov/flask-jwt-oidc","owner":"bcgov","description":"Fork for MDS","archived":false,"fork":true,"pushed_at":"2023-01-16T23:04:38.000Z","size":55,"stargazers_count":0,"open_issues_count":1,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-12-16T17:14:36.533Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":"thorwolpert/flask-jwt-oidc","license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bcgov.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2023-01-16T22:11:37.000Z","updated_at":"2023-01-16T23:04:43.000Z","dependencies_parsed_at":"2023-02-10T06:40:25.308Z","dependency_job_id":null,"html_url":"https://github.com/bcgov/flask-jwt-oidc","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bcgov%2Fflask-jwt-oidc","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bcgov%2Fflask-jwt-oidc/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bcgov%2Fflask-jwt-oidc/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bcgov%2Fflask-jwt-oidc/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bcgov","download_url":"https://codeload.github.com/bcgov/flask-jwt-oidc/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":234929139,"owners_count":18908881,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-09-24T13:50:10.469Z","updated_at":"2025-10-02T02:31:33.222Z","avatar_url":"https://github.com/bcgov.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Flask JWT OIDC\n\n### Simple OIDC JWT extension to protect APIs\nThis is a fairly simple extension that should require minimal setup for OIDC standard services.\n\nCurrently it's testing against Keycloak, but will be adding in example configs and testing for:\n- Keycloak\n- dex\n- Google\n- Amazon IAM\n- Auth0\n\n\n### Alternatives\nThere are some great alternatives that are not so opinionated and provide more support for general JWTs\nCheck out: [**Flask-JWT-Simple**](https://github.com/vimalloc/flask-jwt-simple) \n\n### Example(s)\nThere is one example under\n`example/flask_app`\nIt uses pytest and sets up a dummy JWT to be used in the tests.\n### Configuration\nCreate a .env file,  or OS configmap, shell exports, etc.\n```bash\n#.env\nexport JWT_OIDC_WELL_KNOWN_CONFIG=\"https://KEYCLOAK-SERVICE/auth/realms/REALM-NAME/.well-known/openid-configuration\"\nexport JWT_OIDC_AUDIENCE=\"keycloak-client\"\nexport JWT_OIDC_CLIENT_SECRET=\"keycloak-client-secret\"\n```\n\nCreate a config file, that reads in the environment variables:\n```python\n# config.py\n\nfrom os import environ as env\nfrom dotenv import load_dotenv, find_dotenv\n\n\nENV_FILE = find_dotenv()\nif ENV_FILE:\n    load_dotenv(ENV_FILE)\n\nclass Config(object):\n\n    JWT_OIDC_WELL_KNOWN_CONFIG = env.get('JWT_OIDC_WELL_KNOWN_CONFIG')\n    JWT_OIDC_AUDIENCE = env.get('JWT_OIDC_AUDIENCE')\n    JWT_OIDC_CLIENT_SECRET = env.get('JWT_OIDC_CLIENT_SECRET')\n```\n\nCreate a flask script that to use the JWT services\n\nNote: that roles can be checked as either *decorators* managing access to the function, or as a *function* call that returns True/False for finer grained access control in the body of the function.\n```python\n# app.py\n\nfrom flask import Flask, jsonify\nfrom flask_cors import cross_origin\nfrom config import Config\nfrom flask_jwt_oidc import AuthError, JwtManager\n\n\napp = Flask(__name__)\n\napp.config.from_object(Config)\n\ndef get_roles(dict):\n    return dict['realm_access']['roles']\napp.config['JWT_ROLE_CALLBACK'] = get_roles\n\njwt = JwtManager(app)\n\n@app.route(\"/api/secure\")\n@cross_origin(headers=[\"Content-Type\", \"Authorization\"])\n@cross_origin(headers=[\"Access-Control-Allow-Origin\", \"*\"]) # IRL you'd scope this to set domains\n@jwt.requires_auth\ndef secure():\n    \"\"\"A Bearer JWT is required to get a response from this endpoint\n    \"\"\"\n    return jsonify(message=\"The is a secured endpoint. You provided a valid Bearer JWT to access it.\")\n\n\n@app.route(\"/api/secured-and-roles\")\n@cross_origin(headers=[\"Content-Type\", \"Authorization\"])\n@cross_origin(headers=[\"Access-Control-Allow-Origin\", \"*\"]) # IRL you'd scope this to a real domain\n@jwt.requires_auth\ndef secure_with_roles():\n    \"\"\"valid access token and assigned roles are required\n    \"\"\"\n    if jwt.validate_roles(\"names_editor\"):\n        return jsonify(message=\"This is a secured endpoint, where roles were examined in the body of the procedure! \"\n                               \"You provided a valid JWT token\")\n\n    raise AuthError({\n        \"code\": \"Unauthorized\",\n        \"description\": \"You don't have access to this resource\"\n    }, 403)\n\n\n@app.route(\"/api/secured-decorated-roles\")\n@cross_origin(headers=[\"Content-Type\", \"Authorization\"])\n@cross_origin(headers=[\"Access-Control-Allow-Origin\", \"*\"]) # IRL you'd scope this to a real domain\n@jwt.requires_roles(\"names_editor\")\ndef secure_deco_roles():\n    \"\"\"valid access token and assigned roles are required\n    \"\"\"\n    return jsonify(message=\"This is a secured endpoint. \"\n                           \"The roles were checked before entering the body of the procedure! \"\n                           \"You provided a valid JWT token\")\n\n\nif __name__ == \"__main__\":\n    app.run()\n\n```\n## Thanks\nThe following folks have provided help, feedback, PRs, etc:\n- Jamie Lennox\n- James Hollinger\n\n## TODO\n- add tests\n- add more examples\n- add tests for the OIDC service providers listed above\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbcgov%2Fflask-jwt-oidc","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbcgov%2Fflask-jwt-oidc","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbcgov%2Fflask-jwt-oidc/lists"}