Effortless authentication solution for your services
FastID is responsible for authentication, user management and single account for all your services.
The key features are:
- Security. Built with security in mind. It uses JWT tokens, OAuth 2.0 and OpenID Connect.
- Admin Interface. Comes with an admin interface to manage users and applications.
- Social Login. Supports social login with Google, Telegram, Yandex, and others.
- Notifications. Sends welcome messages and verification codes via email and Telegram.
- Plugins. Offers a plugin system to extend the functionality.
- Observability. Metrics and tracing complied with OpenTelemetry.
- Pythonic. FastID is the best choice for Python apps.
-
Clone the repository:
git clone https://github.com/everysoftware/fastid
-
Generate RSA keys:
mkdir certs openssl genrsa -out certs/jwt-private.pem 2048 openssl rsa -in certs/jwt-private.pem -pubout -out certs/jwt-public.pem
-
Create a
.env
file. Use the.env.example
as a reference. -
Run the application:
make up
-
Enjoy!
To set up observability, you can use this preset.
FastID is available at http://localhost:8012
API docs are available at http://localhost:8012/api/v1/docs
Admin is available at: http://localhost:8012/admin (default credentials:
admin
/admin
)
Create new app in admin to get client_id
and client_secret
.
Here is an example of integration with FastAPI:
from typing import Any, Annotated
from urllib.parse import urlencode
import httpx
from fastapi import FastAPI, Response, Request, Depends, HTTPException
from fastapi.responses import RedirectResponse
from test_client.config import settings
app = FastAPI()
@app.get("/login")
def login(request: Request) -> Any:
params = {
"response_type": "code",
"client_id": settings.client_id,
"redirect_uri": request.url_for("callback"),
}
url = f"{settings.fastid_url}/authorize?{urlencode(params)}"
return RedirectResponse(url=url)
@app.get("/callback")
def callback(code: str) -> Any:
token_data = httpx.post(
f"{settings.fastid_url}/api/v1/token",
headers={"Content-Type": "application/x-www-form-urlencoded"},
data={
"grant_type": "authorization_code",
"client_id": settings.client_id,
"client_secret": settings.client_secret,
"code": code,
},
)
token = token_data.json()
response = Response(content="You are now logged in!")
response.set_cookie("access_token", token["access_token"])
return response
def current_user(request: Request) -> dict[str, Any]:
token = request.cookies.get("access_token")
if not token:
raise HTTPException(401, "No access token")
response = httpx.get(
f"{settings.fastid_url}/api/v1/userinfo",
headers={"Authorization": f"Bearer {token}"},
)
return response.json()
@app.get("/test")
def test(user: Annotated[dict[str, Any], Depends(current_user)]) -> Any:
return user
Run the server:
fastapi dev test_client/app.py
Go to http://localhost:8000/login to login in FastID. You will be redirected to FastID to enter your credentials. After successful login you will be redirected back to the client app and receive an access token.
Now you can access the protected route http://localhost:8000/test:
See the full example in the test_client
directory.
OpenID metadata is available at http://localhost:8012/.well-known/openid-configuration.
{
"issuer": "http://localhost:8012",
"authorization_endpoint": "http://localhost:8012/authorize",
"token_endpoint": "http://localhost:8012/api/v1/token",
"userinfo_endpoint": "http://localhost:8012/api/v1/userinfo",
"jwks_uri": "http://localhost:8012/.well-known/jwks.json",
"scopes_supported": [
"openid",
"email",
"name",
"offline_access"
],
"response_types_supported": [
"code"
],
"grant_types_supported": [
"authorization_code",
"refresh_token"
],
"subject_types_supported": [
"public"
],
"id_token_signing_alg_values_supported": [
"RS256"
],
"claims_supported": [
"iss",
"sub",
"aud",
"typ",
"iat",
"exp",
"name",
"given_name",
"family_name",
"email",
"email_verified"
]
}
Made with ❤️