<h2 align="center">Handle OAuth2 authentication for REST APIs</h2>
<p align="center">
<a href="https://pypi.org/project/layabauth/"><img alt="pypi version" src="https://img.shields.io/pypi/v/layabauth"></a>
<a href="https://github.com/Colin-b/layabauth/actions"><img alt="Build status" src="https://github.com/Colin-b/layabauth/workflows/Release/badge.svg"></a>
<a href="https://github.com/Colin-b/layabauth/actions"><img alt="Coverage" src="https://img.shields.io/badge/coverage-100%25-brightgreen"></a>
<a href="https://github.com/psf/black"><img alt="Code style: black" src="https://img.shields.io/badge/code%20style-black-000000.svg"></a>
<a href="https://github.com/Colin-b/layabauth/actions"><img alt="Number of tests" src="https://img.shields.io/badge/tests-50 passed-blue"></a>
<a href="https://pypi.org/project/layabauth/"><img alt="Number of downloads" src="https://img.shields.io/pypi/dm/layabauth"></a>
</p>
As expected by the HTTP specification, token is extracted from `Authorization` header and must be prefixed with `Bearer `.
Token will then be validated and in case it is valid, you will be able to access the raw token (as string) and the decoded token body (as dictionary).
## Starlette
Provides a [Starlette authentication backend](https://www.starlette.io/authentication/): `layabauth.starlette.OAuth2IdTokenBackend`.
3 arguments are required:
* The [JWKs](https://tools.ietf.org/html/rfc7517) URI as defined in .well-known.
- Azure Active Directory: `https://sts.windows.net/common/discovery/keys`
- Microsoft Identity Platform: `https://sts.windows.net/common/discovery/keys`
* A callable to create the [authenticated user](https://www.starlette.io/authentication/#users) based on received token.
* A callable to returns [authenticated user scopes](https://www.starlette.io/authentication/#permissions) based on received token.
Below is a sample `Starlette` application with an endpoint requesting a Microsoft issued OAuth2 token.
```python
import starlette.applications
from starlette.authentication import SimpleUser, requires
from starlette.middleware import Middleware
from starlette.middleware.authentication import AuthenticationMiddleware
from starlette.responses import PlainTextResponse
import layabauth.starlette
backend = layabauth.starlette.OAuth2IdTokenBackend(
jwks_uri="https://sts.windows.net/common/discovery/keys",
create_user=lambda token, token_body: SimpleUser(token_body["name"]),
scopes=lambda token, token_body: token_body["scopes"]
)
app = starlette.applications.Starlette(middleware=[Middleware(AuthenticationMiddleware, backend=backend)])
@app.route("/my_endpoint")
@requires('my_scope')
async def my_endpoint(request):
return PlainTextResponse(request.user.display_name)
```
## Flask
Provides a decorator `layabauth.flask.requires_authentication` to ensure that, in a context of a `Flask` application, a valid OAuth2 token was received.
The [JWKs](https://tools.ietf.org/html/rfc7517) URI as defined in .well-known is the only required argument.
- Azure Active Directory: `https://sts.windows.net/common/discovery/keys`
- Microsoft Identity Platform: `https://sts.windows.net/common/discovery/keys`
If validation fails, an `werkzeug.exceptions.Unauthorized` exception is raised.
Otherwise token is stored in `flask.g.token` and decoded token body is stored in `flask.g.token_body`.
Decorator works fine on `flask-restplus` methods as well.
Below is a sample `Flask` application with an endpoint requesting a Microsoft issued OAuth2 token.
```python
import flask
import layabauth.flask
app = flask.Flask(__name__)
@app.route("/my_endpoint")
@layabauth.flask.requires_authentication("https://sts.windows.net/common/discovery/keys")
def my_endpoint():
# Optional, ensure that the appropriates scopes are provided
layabauth.flask.requires_scopes(lambda token, token_body: token_body["scopes"], "my_scope")
# Return the content of the name entry within the decoded token body.
return flask.Response(flask.g.token_body["name"])
app.run()
```
## OpenAPI
You can generate OpenAPI 2.0 `security` definition thanks to `layabauth.authorizations`.
You can generate OpenAPI 2.0 `method security` thanks to `layabauth.method_authorizations`
## Testing
Authentication can be mocked using `layabauth.testing.auth_mock` `pytest` fixture.
`token_body` `pytest` fixture returning the decoded token body used in tests must be provided.
`jwks_uri` `pytest` fixture returning the jwks_uri used in tests must be provided.
```python
from layabauth.testing import *
@pytest.fixture
def jwks_uri():
return "https://sts.windows.net/common/discovery/keys"
@pytest.fixture
def token_body():
return {"name": "TEST@email.com", "scopes": ["my_scope"]}
def test_authentication(auth_mock, client):
response = client.get("/my_endpoint", headers={"Authentication": "Bearer mocked_token"})
assert response.text == "TEST@email.com"
```
## How to install
1. [python 3.7+](https://www.python.org/downloads/) must be installed
2. Use pip to install module:
```sh
python -m pip install layabauth
```
Raw data
{
"_id": null,
"home_page": "https://colin-b.github.io/layabauth/",
"name": "layabauth",
"maintainer": "Colin Bounouar",
"docs_url": null,
"requires_python": ">=3.7",
"maintainer_email": "colin.bounouar.dev@gmail.com",
"keywords": "flask,starlette,auth",
"author": "Colin Bounouar",
"author_email": "colin.bounouar.dev@gmail.com",
"download_url": "https://files.pythonhosted.org/packages/dd/45/92b65092baf91541a2635264e19a97e321e6b100ecd085932fc68f192f7d/layabauth-7.0.0.tar.gz",
"platform": "Windows",
"description": "<h2 align=\"center\">Handle OAuth2 authentication for REST APIs</h2>\n\n<p align=\"center\">\n<a href=\"https://pypi.org/project/layabauth/\"><img alt=\"pypi version\" src=\"https://img.shields.io/pypi/v/layabauth\"></a>\n<a href=\"https://github.com/Colin-b/layabauth/actions\"><img alt=\"Build status\" src=\"https://github.com/Colin-b/layabauth/workflows/Release/badge.svg\"></a>\n<a href=\"https://github.com/Colin-b/layabauth/actions\"><img alt=\"Coverage\" src=\"https://img.shields.io/badge/coverage-100%25-brightgreen\"></a>\n<a href=\"https://github.com/psf/black\"><img alt=\"Code style: black\" src=\"https://img.shields.io/badge/code%20style-black-000000.svg\"></a>\n<a href=\"https://github.com/Colin-b/layabauth/actions\"><img alt=\"Number of tests\" src=\"https://img.shields.io/badge/tests-50 passed-blue\"></a>\n<a href=\"https://pypi.org/project/layabauth/\"><img alt=\"Number of downloads\" src=\"https://img.shields.io/pypi/dm/layabauth\"></a>\n</p>\n\nAs expected by the HTTP specification, token is extracted from `Authorization` header and must be prefixed with `Bearer `.\n\nToken will then be validated and in case it is valid, you will be able to access the raw token (as string) and the decoded token body (as dictionary).\n\n## Starlette\n\nProvides a [Starlette authentication backend](https://www.starlette.io/authentication/): `layabauth.starlette.OAuth2IdTokenBackend`.\n\n3 arguments are required:\n* The [JWKs](https://tools.ietf.org/html/rfc7517) URI as defined in .well-known.\n - Azure Active Directory: `https://sts.windows.net/common/discovery/keys`\n - Microsoft Identity Platform: `https://sts.windows.net/common/discovery/keys`\n* A callable to create the [authenticated user](https://www.starlette.io/authentication/#users) based on received token.\n* A callable to returns [authenticated user scopes](https://www.starlette.io/authentication/#permissions) based on received token.\n\nBelow is a sample `Starlette` application with an endpoint requesting a Microsoft issued OAuth2 token.\n\n```python\nimport starlette.applications\nfrom starlette.authentication import SimpleUser, requires\nfrom starlette.middleware import Middleware\nfrom starlette.middleware.authentication import AuthenticationMiddleware\nfrom starlette.responses import PlainTextResponse\n\nimport layabauth.starlette\n\nbackend = layabauth.starlette.OAuth2IdTokenBackend(\n jwks_uri=\"https://sts.windows.net/common/discovery/keys\",\n create_user=lambda token, token_body: SimpleUser(token_body[\"name\"]),\n scopes=lambda token, token_body: token_body[\"scopes\"]\n)\napp = starlette.applications.Starlette(middleware=[Middleware(AuthenticationMiddleware, backend=backend)])\n\n@app.route(\"/my_endpoint\")\n@requires('my_scope')\nasync def my_endpoint(request):\n return PlainTextResponse(request.user.display_name)\n```\n\n## Flask\n\nProvides a decorator `layabauth.flask.requires_authentication` to ensure that, in a context of a `Flask` application, a valid OAuth2 token was received.\n\nThe [JWKs](https://tools.ietf.org/html/rfc7517) URI as defined in .well-known is the only required argument.\n- Azure Active Directory: `https://sts.windows.net/common/discovery/keys`\n- Microsoft Identity Platform: `https://sts.windows.net/common/discovery/keys`\n\nIf validation fails, an `werkzeug.exceptions.Unauthorized` exception is raised.\nOtherwise token is stored in `flask.g.token` and decoded token body is stored in `flask.g.token_body`.\n\nDecorator works fine on `flask-restplus` methods as well.\n\nBelow is a sample `Flask` application with an endpoint requesting a Microsoft issued OAuth2 token.\n\n```python\nimport flask\nimport layabauth.flask\n\napp = flask.Flask(__name__)\n\n@app.route(\"/my_endpoint\")\n@layabauth.flask.requires_authentication(\"https://sts.windows.net/common/discovery/keys\")\ndef my_endpoint():\n # Optional, ensure that the appropriates scopes are provided\n layabauth.flask.requires_scopes(lambda token, token_body: token_body[\"scopes\"], \"my_scope\")\n # Return the content of the name entry within the decoded token body.\n return flask.Response(flask.g.token_body[\"name\"])\n\napp.run()\n```\n\n## OpenAPI\n\nYou can generate OpenAPI 2.0 `security` definition thanks to `layabauth.authorizations`.\n\nYou can generate OpenAPI 2.0 `method security` thanks to `layabauth.method_authorizations`\n\n## Testing\n\nAuthentication can be mocked using `layabauth.testing.auth_mock` `pytest` fixture.\n\n`token_body` `pytest` fixture returning the decoded token body used in tests must be provided.\n`jwks_uri` `pytest` fixture returning the jwks_uri used in tests must be provided.\n\n```python\nfrom layabauth.testing import *\n\n\n@pytest.fixture\ndef jwks_uri():\n return \"https://sts.windows.net/common/discovery/keys\"\n\n\n@pytest.fixture\ndef token_body():\n return {\"name\": \"TEST@email.com\", \"scopes\": [\"my_scope\"]}\n\n\ndef test_authentication(auth_mock, client):\n response = client.get(\"/my_endpoint\", headers={\"Authentication\": \"Bearer mocked_token\"})\n assert response.text == \"TEST@email.com\"\n```\n\n## How to install\n1. [python 3.7+](https://www.python.org/downloads/) must be installed\n2. Use pip to install module:\n```sh\npython -m pip install layabauth\n```\n\n\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "Handle OAuth2 authentication for REST APIs",
"version": "7.0.0",
"split_keywords": [
"flask",
"starlette",
"auth"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "d3d38ad56cf5086f727d413e5a21f0440664570a573a08b15d858aa325a13a5c",
"md5": "51825f30a61acd1026d73aa092fb0281",
"sha256": "3e2fb33ae2d7da1c32e0f7f68bee2091d2a1039d2b2d0b8e33df360558aa2dd9"
},
"downloads": -1,
"filename": "layabauth-7.0.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "51825f30a61acd1026d73aa092fb0281",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.7",
"size": 8540,
"upload_time": "2023-04-26T15:29:25",
"upload_time_iso_8601": "2023-04-26T15:29:25.613230Z",
"url": "https://files.pythonhosted.org/packages/d3/d3/8ad56cf5086f727d413e5a21f0440664570a573a08b15d858aa325a13a5c/layabauth-7.0.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "dd4592b65092baf91541a2635264e19a97e321e6b100ecd085932fc68f192f7d",
"md5": "034820bfb2da46d09af61a4daf81460e",
"sha256": "904ee28d3b9362e9344378feb050f05bcf272eb675adcb9ebeaa218db9367e2b"
},
"downloads": -1,
"filename": "layabauth-7.0.0.tar.gz",
"has_sig": false,
"md5_digest": "034820bfb2da46d09af61a4daf81460e",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.7",
"size": 15195,
"upload_time": "2023-04-26T15:29:26",
"upload_time_iso_8601": "2023-04-26T15:29:26.857644Z",
"url": "https://files.pythonhosted.org/packages/dd/45/92b65092baf91541a2635264e19a97e321e6b100ecd085932fc68f192f7d/layabauth-7.0.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2023-04-26 15:29:26",
"github": false,
"gitlab": false,
"bitbucket": false,
"lcname": "layabauth"
}