Skip to content

Commit

Permalink
bugfix: langflow application losing store api-key on refresh page/bac…
Browse files Browse the repository at this point in the history
…kend (langflow-ai#2960)

* changing api key journey

* refactor(api_key.py): remove unnecessary code related to config_dir and secret_key_path
refactor(login.py): refactor setting api_key cookie to use user's store_api_key
refactor(variable/service.py): re-encrypt stored value if secret_key changes to ensure validity

* 📝 (api_key.py): Remove unused imports and clean up code for better readability
📝 (login.py): Remove unused imports and clean up code for better readability
📝 (auth/utils.py): Remove unused imports and clean up code for better readability
📝 (store/service.py): Remove unused imports and clean up code for better readability

* 🔧 (utils.py): replace hashing logic with random key generation for key length less than 32 bytes to ensure key length is always 32 bytes
📝 (utils.py): update comments for clarity and accuracy regarding key generation and encryption process

---------

Co-authored-by: Gabriel Luiz Freitas Almeida <[email protected]>
  • Loading branch information
Cristhianzl and ogabrielluiz authored Jul 25, 2024
1 parent 55693c9 commit b6774cf
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 2 deletions.
17 changes: 16 additions & 1 deletion src/backend/base/langflow/api/v1/api_key.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from typing import TYPE_CHECKING
from uuid import UUID

from fastapi import APIRouter, Depends, HTTPException
from fastapi import APIRouter, Depends, HTTPException, Response
from sqlmodel import Session

from langflow.api.v1.schemas import ApiKeyCreateRequest, ApiKeysResponse
Expand Down Expand Up @@ -62,17 +62,32 @@ def delete_api_key_route(
@router.post("/store")
def save_store_api_key(
api_key_request: ApiKeyCreateRequest,
response: Response,
current_user: User = Depends(auth_utils.get_current_active_user),
db: Session = Depends(get_session),
settings_service=Depends(get_settings_service),
):
auth_settings = settings_service.auth_settings

try:
api_key = api_key_request.api_key

# Encrypt the API key
encrypted = auth_utils.encrypt_api_key(api_key, settings_service=settings_service)
current_user.store_api_key = encrypted
db.add(current_user)
db.commit()

response.set_cookie(
"apikey_tkn_lflw",
encrypted,
httponly=auth_settings.ACCESS_HTTPONLY,
samesite=auth_settings.ACCESS_SAME_SITE,
secure=auth_settings.ACCESS_SECURE,
expires=None, # Set to None to make it a session cookie
domain=auth_settings.COOKIE_DOMAIN,
)

return {"detail": "API Key saved"}
except Exception as e:
raise HTTPException(status_code=400, detail=str(e)) from e
Expand Down
28 changes: 28 additions & 0 deletions src/backend/base/langflow/api/v1/login.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from fastapi import APIRouter, Depends, HTTPException, Request, Response, status
from fastapi.security import OAuth2PasswordRequestForm
from langflow.services.database.models.user.crud import get_user_by_id
from sqlmodel import Session

from langflow.api.v1.schemas import Token
Expand Down Expand Up @@ -57,6 +58,15 @@ async def login_to_get_access_token(
expires=auth_settings.ACCESS_TOKEN_EXPIRE_SECONDS,
domain=auth_settings.COOKIE_DOMAIN,
)
response.set_cookie(
"apikey_tkn_lflw",
str(user.store_api_key),
httponly=auth_settings.ACCESS_HTTPONLY,
samesite=auth_settings.ACCESS_SAME_SITE,
secure=auth_settings.ACCESS_SECURE,
expires=None, # Set to None to make it a session cookie
domain=auth_settings.COOKIE_DOMAIN,
)
variable_service.initialize_user_variables(user.id, db)
# Create default folder for user if it doesn't exist
create_default_folder_if_it_doesnt_exist(db, user.id)
Expand All @@ -74,6 +84,7 @@ async def auto_login(
response: Response, db: Session = Depends(get_session), settings_service=Depends(get_settings_service)
):
auth_settings = settings_service.auth_settings

if settings_service.auth_settings.AUTO_LOGIN:
user_id, tokens = create_user_longterm_token(db)
response.set_cookie(
Expand All @@ -86,6 +97,22 @@ async def auto_login(
domain=auth_settings.COOKIE_DOMAIN,
)

user = get_user_by_id(db, user_id)

if user:
if user.store_api_key is None:
user.store_api_key = ""

response.set_cookie(
"apikey_tkn_lflw",
str(user.store_api_key), # Ensure it's a string
httponly=auth_settings.ACCESS_HTTPONLY,
samesite=auth_settings.ACCESS_SAME_SITE,
secure=auth_settings.ACCESS_SECURE,
expires=None, # Set to None to make it a session cookie
domain=auth_settings.COOKIE_DOMAIN,
)

return tokens

raise HTTPException(
Expand Down Expand Up @@ -140,4 +167,5 @@ async def refresh_token(
async def logout(response: Response):
response.delete_cookie("refresh_token_lf")
response.delete_cookie("access_token_lf")
response.delete_cookie("apikey_tkn_lflw")
return {"message": "Logout successful"}
1 change: 0 additions & 1 deletion src/frontend/src/contexts/authContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,6 @@ export function AuthProvider({ children }): React.ReactElement {
}

function storeApiKey(apikey: string) {
cookies.set(LANGFLOW_API_TOKEN, apikey, { path: "/" });
setApiKey(apikey);
}

Expand Down

0 comments on commit b6774cf

Please sign in to comment.