Skip to content

Commit

Permalink
Prepare repository for open-source (GH-6)
Browse files Browse the repository at this point in the history
  • Loading branch information
ArtyomVancyan authored Jul 13, 2023
2 parents 1f3248a + 5be639a commit 8bc7781
Show file tree
Hide file tree
Showing 27 changed files with 443 additions and 169 deletions.
28 changes: 28 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: Publish to PyPI

on:
release:
types: [ published ]

jobs:
deploy:

runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v3
with:
python-version: '3.x'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install setuptools wheel twine
- name: Build and publish
env:
TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }}
TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
run: |
python setup.py sdist bdist_wheel
twine upload dist/*
55 changes: 55 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
name: tests

on:
push:
branches: [ master ]
pull_request:
branches: [ master ]

jobs:
test:
runs-on: ${{ matrix.os || 'ubuntu-latest' }}
strategy:
matrix:
include:
- python: "3.6"
env: py36-fastapi68
os: ubuntu-20.04 # 3.6 is not available on ubuntu-20.04
- python: "3.8"
env: py38-fastapi68
- python: "3.10"
env: py310-fastapi68
- python: "3.11"
env: py311-fastapi68

- python: "3.7"
env: py37-fastapi84
- python: "3.9"
env: py39-fastapi84
- python: "3.10"
env: py310-fastapi84
- python: "3.11"
env: py311-fastapi84

- python: "3.7"
env: py37-fastapi99
- python: "3.9"
env: py39-fastapi99
- python: "3.10"
env: py310-fastapi99
- python: "3.11"
env: py311-fastapi99

steps:
- uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python }}
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python }}
- name: Install dependencies
run: |
pip install --upgrade pip
sh build.sh
pip install tox tox-gh-actions
- name: Run tests using tox
run: tox -e ${{ matrix.env }}
16 changes: 16 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# caches
.idea
.tox
.pytest_cache
*.egg-info
__pycache__

# docs
docs/node_modules
docs/package-lock.json
docs/.vitepress/cache
docs/.vitepress/dist

# build
build
dist
115 changes: 97 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,28 +1,107 @@
# fastapi-oauth2
# fastapi-oauth2 <img src="https://github.com/pysnippet.png" align="right" height="64" />

Easy to setup OAuth2 social authentication mechanism with support for several auth providers.
[![PyPI](https://img.shields.io/pypi/v/fastapi-oauth2.svg)](https://pypi.org/project/fastapi-oauth2/)
[![Python](https://img.shields.io/pypi/pyversions/fastapi-oauth2.svg?logoColor=white)](https://pypi.org/project/fastapi-oauth2/)
[![FastAPI](https://img.shields.io/badge/fastapi-%E2%89%A50.68.1-009486)](https://pypi.org/project/fastapi-oauth2/)
[![Tests](https://github.com/pysnippet/fastapi-oauth2/actions/workflows/tests.yml/badge.svg)](https://github.com/pysnippet/fastapi-oauth2/actions/workflows/tests.yml)
[![License](https://img.shields.io/pypi/l/fastapi-oauth2.svg)](https://github.com/pysnippet/fastapi-oauth2/blob/master/LICENSE)

## Demo
FastAPI OAuth2 is a middleware-based social authentication mechanism supporting several auth providers. It depends on
the [social-core](https://github.com/python-social-auth/social-core) authentication backends.

This sample application is made to demonstrate the use of the [**fastapi-oauth2**](./fastapi_oauth2) package.
## Features to be implemented

## Running the application
- Use multiple OAuth2 providers at the same time
* There need to be provided a way to configure the OAuth2 for multiple providers
- Provide `fastapi.security.*` implementations that use cookies
- Token -> user data, user data -> token easy conversion
- Customizable OAuth2 routes
- Registration support

## Installation

```bash
uvicorn main:app --reload
```shell
python -m pip install fastapi-oauth2
```

## TODO
## Configuration

- Make the [**fastapi-oauth2**](./fastapi_oauth2) depend
on (overuse) the [**social-core**](https://github.com/python-social-auth/social-core)
Configuration requires you to provide the JWT requisites and define the clients of the particular providers. The
middleware configuration is declared with the `OAuth2Config` and `OAuth2Client` classes.

## Features
### OAuth2Config

- Integrate with any existing FastAPI project (no dependencies of the project should stop the work of
the `fastapi-oauth2`)
* Implementation must allow to provide a context for configurations (also, see how it is done in another projects)
- Use multiple OAuth2 providers at the same time
* There need to be provided a way to configure the OAuth2 for multiple providers
- Token -> user data, user data -> token easy conversion
- Customize OAuth2 routes
- `allow_http` - Allow insecure HTTP requests. Defaults to `False`.
- `jwt_secret` - The secret key used to sign the JWT. Defaults to `None`.
- `jwt_expires` - The expiration time of the JWT in seconds. Defaults to `900`.
- `jwt_algorithm` - The algorithm used to sign the JWT. Defaults to `HS256`.
- `clients` - The list of the OAuth2 clients. Defaults to `[]`.

### OAuth2Client

- `backend` - The [social-core](https://github.com/python-social-auth/social-core) authentication backend classname.
- `client_id` - The OAuth2 client ID for the particular provider.
- `client_secret` - The OAuth2 client secret for the particular provider.
- `redirect_uri` - The OAuth2 redirect URI to redirect to after success. Defaults to the base URL.
- `scope` - The OAuth2 scope for the particular provider. Defaults to `[]`.

It is also important to mention that for the configured clients of the auth providers, the authorization URLs are
accessible by the `/oauth2/{provider}/auth` path where the `provider` variable represents the exact value of the auth
provider backend `name` attribute.

```python
from fastapi_oauth2.client import OAuth2Client
from fastapi_oauth2.config import OAuth2Config
from social_core.backends.github import GithubOAuth2

oauth2_config = OAuth2Config(
allow_http=False,
jwt_secret=os.getenv("JWT_SECRET"),
jwt_expires=os.getenv("JWT_EXPIRES"),
jwt_algorithm=os.getenv("JWT_ALGORITHM"),
clients=[
OAuth2Client(
backend=GithubOAuth2,
client_id=os.getenv("OAUTH2_CLIENT_ID"),
client_secret=os.getenv("OAUTH2_CLIENT_SECRET"),
redirect_uri="https://pysnippet.org/",
scope=["user:email"],
),
]
)
```

## Integration

To integrate the package into your FastAPI application, you need to add the `OAuth2Middleware` with particular configs
in the above-represented format and include the router to the main router of the application.

```python
from fastapi import FastAPI
from fastapi_oauth2.middleware import OAuth2Middleware
from fastapi_oauth2.router import router as oauth2_router

app = FastAPI()
app.include_router(oauth2_router)
app.add_middleware(OAuth2Middleware, config=oauth2_config)
```

After adding the middleware, the `user` attribute will be available in the request context. It will contain the user
data provided by the OAuth2 provider.

```jinja2
{% if request.user.is_authenticated %}
<a href="/oauth2/logout">Sign out</a>
{% else %}
<a href="/oauth2/github/auth">Sign in</a>
{% endif %}
```

## Contribute

Any contribution is welcome. If you have any ideas or suggestions, feel free to open an issue or a pull request. And
don't forget to add tests for your changes.

## License

Copyright (C) 2023 Artyom Vancyan. [MIT](https://github.com/pysnippet/fastapi-oauth2/blob/master/LICENSE)
39 changes: 0 additions & 39 deletions demo/dependencies.py

This file was deleted.

17 changes: 0 additions & 17 deletions demo/router.py

This file was deleted.

1 change: 0 additions & 1 deletion .env → examples/demonstration/.env
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
OAUTH2_CLIENT_ID=eccd08d6736b7999a32a
OAUTH2_CLIENT_SECRET=642999c1c5f2b3df8b877afdc78252ef5b594d31
OAUTH2_CALLBACK_URL=http://127.0.0.1:8000/oauth2/token

JWT_SECRET=secret
JWT_ALGORITHM=HS256
Expand Down
27 changes: 27 additions & 0 deletions examples/demonstration/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
## Demonstration

This sample application is made to demonstrate the use of
the [**fastapi-oauth2**](https://github.com/pysnippet/fastapi-oauth2) package.

## Installation

You got to have `fastapi-oauth2` installed in your environment. To do so, run the following command in
the `pyproject.toml` file's directory.

### Regular install

```bash
pip install fastapi-oauth2
```

### Install in editable mode

```bash
pip install -e .
```

## Running the application

```bash
uvicorn main:app --reload
```
25 changes: 25 additions & 0 deletions examples/demonstration/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import os

from dotenv import load_dotenv
from social_core.backends.github import GithubOAuth2

from fastapi_oauth2.client import OAuth2Client
from fastapi_oauth2.config import OAuth2Config

load_dotenv()

oauth2_config = OAuth2Config(
allow_http=True,
jwt_secret=os.getenv("JWT_SECRET"),
jwt_expires=os.getenv("JWT_EXPIRES"),
jwt_algorithm=os.getenv("JWT_ALGORITHM"),
clients=[
OAuth2Client(
backend=GithubOAuth2,
client_id=os.getenv("OAUTH2_CLIENT_ID"),
client_secret=os.getenv("OAUTH2_CLIENT_SECRET"),
# redirect_uri="http://127.0.0.1:8000/",
scope=["user:email"],
),
]
)
14 changes: 14 additions & 0 deletions examples/demonstration/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
from fastapi import APIRouter
from fastapi import FastAPI

from config import oauth2_config
from fastapi_oauth2.middleware import OAuth2Middleware
from fastapi_oauth2.router import router as oauth2_router
from router import router as app_router

router = APIRouter()

app = FastAPI()
app.include_router(app_router)
app.include_router(oauth2_router)
app.add_middleware(OAuth2Middleware, config=oauth2_config)
21 changes: 21 additions & 0 deletions examples/demonstration/router.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import json

from fastapi import Depends
from fastapi import Request, APIRouter
from fastapi.responses import HTMLResponse
from fastapi.security import OAuth2
from fastapi.templating import Jinja2Templates

oauth2 = OAuth2()
router = APIRouter()
templates = Jinja2Templates(directory="templates")


@router.get("/", response_class=HTMLResponse)
async def root(request: Request):
return templates.TemplateResponse("index.html", {"request": request, "user": request.user, "json": json})


@router.get("/user")
def user(request: Request, _: str = Depends(oauth2)):
return request.user
Loading

0 comments on commit 8bc7781

Please sign in to comment.