-
-
Notifications
You must be signed in to change notification settings - Fork 6.6k
This issue was moved to a discussion.
You can continue the conversation there. Go to discussion →
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
Keycloak integration #1428
Comments
I managed to get part of this working, specifically checking if the token is valid with the help of the python-keycloak library.
|
keycloak_url = "http://127.0.0.1:8080/auth/"
realm = "test"
oauth2_scheme = OAuth2AuthorizationCodeBearer(
authorizationUrl=f"{keycloak_url}realms/{realm}/protocol/openid-connect/auth",
tokenUrl=f"{keycloak_url}realms/{realm}/protocol/openid-connect/token",
) |
Hi guys, Supposing I want to do the following: Which informations vue should send to fastapi ? Do I need to use Using oauth2_scheme, it asks the following: On frontend client I selected public access. I don't have client secret in this case. |
Below is what I am currently using for FasAPI/Vue/KeyCloak. Firstly, I've got an auth file which contains the logic: # ./auth.py
from fastapi.security import OAuth2AuthorizationCodeBearer
from keycloak import KeycloakOpenID # pip require python-keycloak
from .config import settings
from fastapi import Security, HTTPException, status
from pydantic import Json
from .models import User
# This is just for fastapi docs
oauth2_scheme = OAuth2AuthorizationCodeBearer(
authorizationUrl=settings.auth.authorization_url, # https://sso.example.com/auth/
tokenUrl=settings.auth.token_url, # https://sso.example.com/auth/realms/example-realm/protocol/openid-connect/token
)
# This actually does the auth checks
keycloak_openid = KeycloakOpenID(
server_url=settings.auth.server_url, # https://sso.example.com/auth/
client_id=settings.auth.client_id, # backend-client-id
realm_name=settings.auth.realm, # example-realm
client_secret_key=settings.auth.client_secret, # your backend client secret
verify=True
)
async def get_idp_public_key():
return (
"-----BEGIN PUBLIC KEY-----\n"
f"{keycloak_openid.public_key()}"
"\n-----END PUBLIC KEY-----"
)
async def get_auth(token: str = Security(oauth2_scheme)) -> Json:
try:
return keycloak_openid.decode_token(
token,
key= await get_idp_public_key(),
options={
"verify_signature": True,
"verify_aud": True,
"exp": True
}
)
except Exception as e:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail=str(e), # "Invalid authentication credentials",
headers={"WWW-Authenticate": "Bearer"},
)
async def get_current_user(
identity: Json = Depends(get_auth)
) -> User:
return User.first_or_fail(identity['sub']) # get your user form the DB using identity['sub']
Then you can optionally set a default client ID for the docs (which is useful for development) # /main.py
from fastapi import FastAPI
from .config import settings
app = FastAPI(
title=settings.project_name,
debug=settings.app_debug,
openapi_url=f"{settings.api_v1_str}/openapi.json",
swagger_ui_init_oauth = {
# If you are using pkce (which you should be)
"usePkceWithAuthorizationCodeGrant": True,
# Auth fill client ID for the docs with the below value
"clientId": settings.auth.docs_client_id, # example-frontend-client-id-for-dev
"scopes": settings.auth.scopes # [required scopes here]
}
) Now you can protect individual routes by adding # global route collection
api_router = APIRouter(default_response_class=JSONResponse)
public_routes = APIRouter()
authenticated_routes = APIRouter()
authenticated_routes.include_router(
user_router, prefix='/user', tags=['User']
)
api_router.include_router(
public_routes
)
api_router.include_router(
authenticated_routes,
dependencies=[Depends(get_auth)]
)
app.include_router(api_router, prefix="/api/v1") When using the docs to test your api, the client ID should now autofill the above value and you can leave the client secret blank (as we don't have one for public clients). One caveat though, is that I haven't worked out how to make the docs refresh the access token. There is a Then on the Vue frontend side, I'm using: import VueKeycloakJs from '@dsb-norge/vue-keycloak-js'
import router from './router'
import Vue from 'vue'
import App from './App'
Vue.config.productionTip = false
Vue.use(VueKeycloakJs, {
logout: {
redirectUri: `${process.env.VUE_APP_BASE_URL}` // Your home page
},
init: {
onLoad: 'login-required', // or 'check-sso' if you only want to protect some routes
pkceMethod: 'S256',
enableLogging: false // set to true for debugging
},
config: {
url: `${process.env.VUE_APP_OIDC_URL}`, // https://sso.example.com/auth/
clientId: `${process.env.VUE_APP_OIDC_CLIENT_ID}`, // frontend-client-id
realm: `${process.env.VUE_APP_OIDC_REALM}` // example-realm
},
onInitError: () => {
console.log('Error Loading Auth')
}
})
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
Hope that helps! |
Hi @pet1330, Thank you for your reply. In this example, which access type are you using on each keycloak client (backend and frontend) ? I have to create two client inside a realm in keycloak: On backend side (fastapi) I defined the client as bearer-only - in that case keycloak will not attempt to authenticate users, but only verify bearer tokens. On frontend side (vue), I defined the client as public - in that case user should login via GUI then only generate the token. The updateToken function is handled using vue : vue - keycloak In my case, because I defined public access type on frontend client, and bearer-only access type to backend, I don't have a As you mentioned, it seems Thank you very much to share your approach. |
The # This is just for fastapi docs
oauth2_scheme = OAuth2AuthorizationCodeBearer(
authorizationUrl=settings.auth.authorization_url, # https://sso.example.com/auth/
tokenUrl=settings.auth.token_url, # https://sso.example.com/auth/realms/example-realm/protocol/openid-connect/token
)
# This actually does the auth checks
keycloak_openid = KeycloakOpenID(
server_url=settings.auth.server_url, # https://sso.example.com/auth/
client_id=settings.auth.client_id, # backend-client-id
realm_name=settings.auth.realm, # example-realm
+ # client_secret_key=settings.auth.client_secret,
- client_secret_key=settings.auth.client_secret,
verify=True
) In our case, we use dsb-norge/vue-keycloak-js to automatically handle refreshing the access token, but your gist above should also work 😃 |
Hi @pet1330, thanks again. When I set Using confidential access type on backend, it seems to pass: I don't know if I am doing something wrong. |
You can't use your FastAPI (your bearer only client ID) on the You should think of the So you should add your bearer-only token to the |
Hi @pet1330, it worked using a public (frontend) client ID. I was having a problem related to I will make some more tests with vue, in order to understand a good way to send token information via API using axios. Thank you very much for helping me. |
Unfortunately Swagger UI still seems unable to automatically refresh the access tokens when they are expired: |
I was integrating keycloak into my project and following the steps I have seen here it works, but when I want to test the authentication with swagger, I get the following error "Invalid parameter: redirect_uri". Did anything similar happen to you? Thanks a bunch for your approaches! |
@aguilarpablo, I think this might be an issue with your keycloak client setup. When you view the client in the keycloak admin, check what value you have for "Valid Redirect URIs", as this is a list of allowed redirect values. Ideally, this should be exactly the location you want the client to redirect to (and should match your client config), but off the top of my head I think you may also be able to put a |
This issue was moved to a discussion.
You can continue the conversation there. Go to discussion →
First check
I used the GitHub search to find a similar issue and didn't find it.
I searched the FastAPI documentation, with the integrated search.
I already searched in Google "How to X in FastAPI" and didn't find any information.
Description
I have to implement a secure API using Keycloak as authentication provider. By reading the documentation i understood that for implementing third party authorization providers is mandatory to build a dependence to inject in the API I want to protect. Can you please explain me better what should i do from Fastapi to obtain a Keycloack token and check if it's valid or not? Cause OAuth2 it's a big topic and i'm a little confused
The text was updated successfully, but these errors were encountered: