Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

replace with authlib #1

Open
Lexachoc opened this issue Jul 8, 2024 · 0 comments
Open

replace with authlib #1

Lexachoc opened this issue Jul 8, 2024 · 0 comments

Comments

@Lexachoc
Copy link
Collaborator

Lexachoc commented Jul 8, 2024

Hi @JannisGrundmann,
As you mentioned last time about authlib.
Below is a minimal code snippet for using authlib with FastAPI and Keycloak.

I already tested locally and it works.
Not sure if authlib is better to replace the current auth library. what do you think?

.env

KEYCLOAK_CLIENT_ID={client_id}
KEYCLOAK_CLIENT_SECRET={client_secret}

main.py

import httpx

from authlib.integrations.base_client import OAuthError
from fastapi import FastAPI, Request
from starlette.config import Config
from starlette.middleware.sessions import SessionMiddleware
from starlette.responses import JSONResponse, RedirectResponse
from fastapi.responses import HTMLResponse
from starlette.templating import Jinja2Templates

from authlib.integrations.starlette_client import OAuth


app = FastAPI()
app.add_middleware(SessionMiddleware, secret_key="{secret_key}", https_only=True) # TODO {secret_key}

config = Config('.env')  # read config from .env file
oauth = OAuth(config)
oauth.register(
    name='keycloak',
    server_metadata_url='http://localhost:8080/realms/{realm_name}/.well-known/openid-configuration', # TODO {realm_name}
    client_kwargs={
        'scope': 'openid email profile'
    }
)

templates = Jinja2Templates(directory="src")

@app.head("/")
@app.get("/")
async def home(request: Request):
    user = request.session.get('user')
    if user:
        # role-based control
        required_roles = ["App-insider", "App-admin"]
        roles = user.get('realm_access', {}).get('roles', [])
        if any(role in roles for role in required_roles):
            return JSONResponse(user)
        else:
            return templates.TemplateResponse("403-visitor.html", {"request": request}, status_code=403)

        # return JSONResponse(user)

    return HTMLResponse('<a href="/login">login</a>')


@app.get('/login')
async def login(request: Request):
    redirect_uri = request.url_for('auth')
    try:
        return await oauth.keycloak.authorize_redirect(request, redirect_uri)
    except httpx.HTTPError as exc:
        return JSONResponse(content=f"HTTP Exception for {exc.request.url} - {exc}", status_code=400)


@app.get('/auth')
async def auth(request: Request):
    try:
        token = await oauth.keycloak.authorize_access_token(request)
    except OAuthError as error:
        return JSONResponse(content=error.error, status_code=400)
    user = token.get('userinfo')
    if user:
        request.session['user'] = dict(user)
    return RedirectResponse(url='/')


@app.get('/logout')
async def logout(request: Request):
    request.session.pop('user', None)
    return RedirectResponse(url='/')

reference: https://github.com/authlib/demo-oauth-client/tree/master/fastapi-google-login

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant