layabauth


Namelayabauth JSON
Version 7.0.0 PyPI version JSON
download
home_pagehttps://colin-b.github.io/layabauth/
SummaryHandle OAuth2 authentication for REST APIs
upload_time2023-04-26 15:29:26
maintainerColin Bounouar
docs_urlNone
authorColin Bounouar
requires_python>=3.7
licenseMIT
keywords flask starlette auth
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            <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"
}
        
Elapsed time: 0.17811s