Effortless authentication solution for your services
- Security. Built with security in mind. It uses JWT tokens, OAuth 2.0 and OpenID Connect.
- Admin Panel. Comes with an admin interface to manage users and applications.
- Notifications. Sends welcome messages and verification codes via email and Telegram.
- Observability. Metrics and tracing complied with OpenTelemetry.
- Social Login. Supports social login with Google, Telegram, Yandex, and others.
- Plugins. Offers a plugin system to extend the functionality.
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 based on .env.example
and run the server:
make up
FastID is available at http://localhost:8012:
Admin panel is available at: http://localhost:8012/admin (default credentials:
admin
/admin
):
To set up observability, you can use this preset.
Enjoy! 🚀
Login to admin panel: http://localhost:8012/admin and create new app to obtain
client_id
and client_secret
.
Here is an example of client app that uses FastID for authentication:
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.
API docs are available at http://localhost:8012/api/v1/docs
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 ❤️