Skip to content

Commit 8bc7781

Browse files
Prepare repository for open-source (GH-6)
2 parents 1f3248a + 5be639a commit 8bc7781

27 files changed

+443
-169
lines changed

.github/workflows/publish.yml

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
name: Publish to PyPI
2+
3+
on:
4+
release:
5+
types: [ published ]
6+
7+
jobs:
8+
deploy:
9+
10+
runs-on: ubuntu-latest
11+
12+
steps:
13+
- uses: actions/checkout@v3
14+
- name: Set up Python
15+
uses: actions/setup-python@v3
16+
with:
17+
python-version: '3.x'
18+
- name: Install dependencies
19+
run: |
20+
python -m pip install --upgrade pip
21+
pip install setuptools wheel twine
22+
- name: Build and publish
23+
env:
24+
TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }}
25+
TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
26+
run: |
27+
python setup.py sdist bdist_wheel
28+
twine upload dist/*

.github/workflows/tests.yml

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
name: tests
2+
3+
on:
4+
push:
5+
branches: [ master ]
6+
pull_request:
7+
branches: [ master ]
8+
9+
jobs:
10+
test:
11+
runs-on: ${{ matrix.os || 'ubuntu-latest' }}
12+
strategy:
13+
matrix:
14+
include:
15+
- python: "3.6"
16+
env: py36-fastapi68
17+
os: ubuntu-20.04 # 3.6 is not available on ubuntu-20.04
18+
- python: "3.8"
19+
env: py38-fastapi68
20+
- python: "3.10"
21+
env: py310-fastapi68
22+
- python: "3.11"
23+
env: py311-fastapi68
24+
25+
- python: "3.7"
26+
env: py37-fastapi84
27+
- python: "3.9"
28+
env: py39-fastapi84
29+
- python: "3.10"
30+
env: py310-fastapi84
31+
- python: "3.11"
32+
env: py311-fastapi84
33+
34+
- python: "3.7"
35+
env: py37-fastapi99
36+
- python: "3.9"
37+
env: py39-fastapi99
38+
- python: "3.10"
39+
env: py310-fastapi99
40+
- python: "3.11"
41+
env: py311-fastapi99
42+
43+
steps:
44+
- uses: actions/checkout@v2
45+
- name: Set up Python ${{ matrix.python }}
46+
uses: actions/setup-python@v2
47+
with:
48+
python-version: ${{ matrix.python }}
49+
- name: Install dependencies
50+
run: |
51+
pip install --upgrade pip
52+
sh build.sh
53+
pip install tox tox-gh-actions
54+
- name: Run tests using tox
55+
run: tox -e ${{ matrix.env }}

.gitignore

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# caches
2+
.idea
3+
.tox
4+
.pytest_cache
5+
*.egg-info
6+
__pycache__
7+
8+
# docs
9+
docs/node_modules
10+
docs/package-lock.json
11+
docs/.vitepress/cache
12+
docs/.vitepress/dist
13+
14+
# build
15+
build
16+
dist

README.md

+97-18
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,107 @@
1-
# fastapi-oauth2
1+
# fastapi-oauth2 <img src="https://github.com/pysnippet.png" align="right" height="64" />
22

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

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

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

9-
## Running the application
14+
- Use multiple OAuth2 providers at the same time
15+
* There need to be provided a way to configure the OAuth2 for multiple providers
16+
- Provide `fastapi.security.*` implementations that use cookies
17+
- Token -> user data, user data -> token easy conversion
18+
- Customizable OAuth2 routes
19+
- Registration support
20+
21+
## Installation
1022

11-
```bash
12-
uvicorn main:app --reload
23+
```shell
24+
python -m pip install fastapi-oauth2
1325
```
1426

15-
## TODO
27+
## Configuration
1628

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

20-
## Features
32+
### OAuth2Config
2133

22-
- Integrate with any existing FastAPI project (no dependencies of the project should stop the work of
23-
the `fastapi-oauth2`)
24-
* Implementation must allow to provide a context for configurations (also, see how it is done in another projects)
25-
- Use multiple OAuth2 providers at the same time
26-
* There need to be provided a way to configure the OAuth2 for multiple providers
27-
- Token -> user data, user data -> token easy conversion
28-
- Customize OAuth2 routes
34+
- `allow_http` - Allow insecure HTTP requests. Defaults to `False`.
35+
- `jwt_secret` - The secret key used to sign the JWT. Defaults to `None`.
36+
- `jwt_expires` - The expiration time of the JWT in seconds. Defaults to `900`.
37+
- `jwt_algorithm` - The algorithm used to sign the JWT. Defaults to `HS256`.
38+
- `clients` - The list of the OAuth2 clients. Defaults to `[]`.
39+
40+
### OAuth2Client
41+
42+
- `backend` - The [social-core](https://github.com/python-social-auth/social-core) authentication backend classname.
43+
- `client_id` - The OAuth2 client ID for the particular provider.
44+
- `client_secret` - The OAuth2 client secret for the particular provider.
45+
- `redirect_uri` - The OAuth2 redirect URI to redirect to after success. Defaults to the base URL.
46+
- `scope` - The OAuth2 scope for the particular provider. Defaults to `[]`.
47+
48+
It is also important to mention that for the configured clients of the auth providers, the authorization URLs are
49+
accessible by the `/oauth2/{provider}/auth` path where the `provider` variable represents the exact value of the auth
50+
provider backend `name` attribute.
51+
52+
```python
53+
from fastapi_oauth2.client import OAuth2Client
54+
from fastapi_oauth2.config import OAuth2Config
55+
from social_core.backends.github import GithubOAuth2
56+
57+
oauth2_config = OAuth2Config(
58+
allow_http=False,
59+
jwt_secret=os.getenv("JWT_SECRET"),
60+
jwt_expires=os.getenv("JWT_EXPIRES"),
61+
jwt_algorithm=os.getenv("JWT_ALGORITHM"),
62+
clients=[
63+
OAuth2Client(
64+
backend=GithubOAuth2,
65+
client_id=os.getenv("OAUTH2_CLIENT_ID"),
66+
client_secret=os.getenv("OAUTH2_CLIENT_SECRET"),
67+
redirect_uri="https://pysnippet.org/",
68+
scope=["user:email"],
69+
),
70+
]
71+
)
72+
```
73+
74+
## Integration
75+
76+
To integrate the package into your FastAPI application, you need to add the `OAuth2Middleware` with particular configs
77+
in the above-represented format and include the router to the main router of the application.
78+
79+
```python
80+
from fastapi import FastAPI
81+
from fastapi_oauth2.middleware import OAuth2Middleware
82+
from fastapi_oauth2.router import router as oauth2_router
83+
84+
app = FastAPI()
85+
app.include_router(oauth2_router)
86+
app.add_middleware(OAuth2Middleware, config=oauth2_config)
87+
```
88+
89+
After adding the middleware, the `user` attribute will be available in the request context. It will contain the user
90+
data provided by the OAuth2 provider.
91+
92+
```jinja2
93+
{% if request.user.is_authenticated %}
94+
<a href="/oauth2/logout">Sign out</a>
95+
{% else %}
96+
<a href="/oauth2/github/auth">Sign in</a>
97+
{% endif %}
98+
```
99+
100+
## Contribute
101+
102+
Any contribution is welcome. If you have any ideas or suggestions, feel free to open an issue or a pull request. And
103+
don't forget to add tests for your changes.
104+
105+
## License
106+
107+
Copyright (C) 2023 Artyom Vancyan. [MIT](https://github.com/pysnippet/fastapi-oauth2/blob/master/LICENSE)

demo/dependencies.py

-39
This file was deleted.

demo/router.py

-17
This file was deleted.

.env renamed to examples/demonstration/.env

-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
OAUTH2_CLIENT_ID=eccd08d6736b7999a32a
22
OAUTH2_CLIENT_SECRET=642999c1c5f2b3df8b877afdc78252ef5b594d31
3-
OAUTH2_CALLBACK_URL=http://127.0.0.1:8000/oauth2/token
43

54
JWT_SECRET=secret
65
JWT_ALGORITHM=HS256

examples/demonstration/README.md

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
## Demonstration
2+
3+
This sample application is made to demonstrate the use of
4+
the [**fastapi-oauth2**](https://github.com/pysnippet/fastapi-oauth2) package.
5+
6+
## Installation
7+
8+
You got to have `fastapi-oauth2` installed in your environment. To do so, run the following command in
9+
the `pyproject.toml` file's directory.
10+
11+
### Regular install
12+
13+
```bash
14+
pip install fastapi-oauth2
15+
```
16+
17+
### Install in editable mode
18+
19+
```bash
20+
pip install -e .
21+
```
22+
23+
## Running the application
24+
25+
```bash
26+
uvicorn main:app --reload
27+
```

examples/demonstration/config.py

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import os
2+
3+
from dotenv import load_dotenv
4+
from social_core.backends.github import GithubOAuth2
5+
6+
from fastapi_oauth2.client import OAuth2Client
7+
from fastapi_oauth2.config import OAuth2Config
8+
9+
load_dotenv()
10+
11+
oauth2_config = OAuth2Config(
12+
allow_http=True,
13+
jwt_secret=os.getenv("JWT_SECRET"),
14+
jwt_expires=os.getenv("JWT_EXPIRES"),
15+
jwt_algorithm=os.getenv("JWT_ALGORITHM"),
16+
clients=[
17+
OAuth2Client(
18+
backend=GithubOAuth2,
19+
client_id=os.getenv("OAUTH2_CLIENT_ID"),
20+
client_secret=os.getenv("OAUTH2_CLIENT_SECRET"),
21+
# redirect_uri="http://127.0.0.1:8000/",
22+
scope=["user:email"],
23+
),
24+
]
25+
)

examples/demonstration/main.py

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
from fastapi import APIRouter
2+
from fastapi import FastAPI
3+
4+
from config import oauth2_config
5+
from fastapi_oauth2.middleware import OAuth2Middleware
6+
from fastapi_oauth2.router import router as oauth2_router
7+
from router import router as app_router
8+
9+
router = APIRouter()
10+
11+
app = FastAPI()
12+
app.include_router(app_router)
13+
app.include_router(oauth2_router)
14+
app.add_middleware(OAuth2Middleware, config=oauth2_config)

examples/demonstration/router.py

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import json
2+
3+
from fastapi import Depends
4+
from fastapi import Request, APIRouter
5+
from fastapi.responses import HTMLResponse
6+
from fastapi.security import OAuth2
7+
from fastapi.templating import Jinja2Templates
8+
9+
oauth2 = OAuth2()
10+
router = APIRouter()
11+
templates = Jinja2Templates(directory="templates")
12+
13+
14+
@router.get("/", response_class=HTMLResponse)
15+
async def root(request: Request):
16+
return templates.TemplateResponse("index.html", {"request": request, "user": request.user, "json": json})
17+
18+
19+
@router.get("/user")
20+
def user(request: Request, _: str = Depends(oauth2)):
21+
return request.user

0 commit comments

Comments
 (0)