2025-05-15 19:49:42 -07:00
import structlog
2025-10-08 14:39:15 -06:00
from fastapi import BackgroundTasks , Body , Depends , HTTPException , Path , Query
2025-05-15 19:49:42 -07:00
2025-10-10 10:10:18 -06:00
from skyvern . config import settings
2025-05-15 19:49:42 -07:00
from skyvern . forge import app
2025-08-05 07:34:26 -07:00
from skyvern . forge . sdk . db . enums import OrganizationAuthTokenType
2025-05-18 13:45:46 -07:00
from skyvern . forge . sdk . routes . code_samples import (
2025-10-28 17:43:19 -06:00
CREATE_CREDENTIAL_CODE_SAMPLE_CREDIT_CARD_PYTHON ,
CREATE_CREDENTIAL_CODE_SAMPLE_CREDIT_CARD_TS ,
CREATE_CREDENTIAL_CODE_SAMPLE_PYTHON ,
CREATE_CREDENTIAL_CODE_SAMPLE_TS ,
DELETE_CREDENTIAL_CODE_SAMPLE_PYTHON ,
DELETE_CREDENTIAL_CODE_SAMPLE_TS ,
GET_CREDENTIAL_CODE_SAMPLE_PYTHON ,
GET_CREDENTIAL_CODE_SAMPLE_TS ,
GET_CREDENTIALS_CODE_SAMPLE_PYTHON ,
GET_CREDENTIALS_CODE_SAMPLE_TS ,
SEND_TOTP_CODE_CODE_SAMPLE_PYTHON ,
SEND_TOTP_CODE_CODE_SAMPLE_TS ,
2025-05-18 13:45:46 -07:00
)
2025-05-15 19:49:42 -07:00
from skyvern . forge . sdk . routes . routers import base_router , legacy_base_router
from skyvern . forge . sdk . schemas . credentials import (
CreateCredentialRequest ,
CredentialResponse ,
CredentialType ,
2025-10-10 10:10:18 -06:00
CredentialVaultType ,
2025-05-15 19:49:42 -07:00
CreditCardCredentialResponse ,
PasswordCredentialResponse ,
)
2025-08-05 07:34:26 -07:00
from skyvern . forge . sdk . schemas . organizations import (
2025-09-23 10:16:48 -06:00
AzureClientSecretCredentialResponse ,
CreateAzureClientSecretCredentialRequest ,
2025-08-05 07:34:26 -07:00
CreateOnePasswordTokenRequest ,
CreateOnePasswordTokenResponse ,
Organization ,
)
2025-10-14 16:24:14 +08:00
from skyvern . forge . sdk . schemas . totp_codes import OTPType , TOTPCode , TOTPCodeCreate
2025-05-15 19:49:42 -07:00
from skyvern . forge . sdk . services import org_auth_service
from skyvern . forge . sdk . services . bitwarden import BitwardenService
2025-10-10 10:10:18 -06:00
from skyvern . forge . sdk . services . credential . credential_vault_service import CredentialVaultService
2025-10-14 16:24:14 +08:00
from skyvern . services . otp_service import OTPValue , parse_otp_login
2025-05-15 19:49:42 -07:00
LOG = structlog . get_logger ( )
2025-10-08 14:39:15 -06:00
async def fetch_credential_item_background ( item_id : str ) - > None :
"""
Background task to fetch the recently added credential item from Bitwarden .
This triggers Bitwarden to sync the vault earlier so the next request does not have to wait for the sync .
"""
try :
LOG . info ( " Pre-fetching credential item from Bitwarden in background " , item_id = item_id )
credential_item = await BitwardenService . get_credential_item ( item_id )
LOG . info ( " Successfully fetched credential item from Bitwarden " , item_id = item_id , name = credential_item . name )
except Exception as e :
LOG . exception ( " Failed to fetch credential item from Bitwarden in background " , item_id = item_id , error = str ( e ) )
2025-07-15 02:01:23 -07:00
@legacy_base_router.post ( " /totp " )
2025-05-15 19:49:42 -07:00
@legacy_base_router.post ( " /totp/ " , include_in_schema = False )
@base_router.post (
" /credentials/totp " ,
response_model = TOTPCode ,
2025-07-15 02:05:33 -07:00
summary = " Send TOTP code " ,
2025-05-21 20:06:34 -07:00
description = " Forward a TOTP (2FA, MFA) email or sms message containing the code to Skyvern. This endpoint stores the code in database so that Skyvern can use it while running tasks/workflows. " ,
2025-05-15 19:49:42 -07:00
tags = [ " Credentials " ] ,
openapi_extra = {
" x-fern-sdk-method-name " : " send_totp_code " ,
2025-10-28 17:43:19 -06:00
" x-fern-examples " : [
{
" code-samples " : [
{ " sdk " : " python " , " code " : SEND_TOTP_CODE_CODE_SAMPLE_PYTHON } ,
{ " sdk " : " typescript " , " code " : SEND_TOTP_CODE_CODE_SAMPLE_TS } ,
]
}
] ,
2025-05-15 19:49:42 -07:00
} ,
)
2025-05-18 13:45:46 -07:00
@base_router.post (
" /credentials/totp/ " ,
response_model = TOTPCode ,
include_in_schema = False ,
)
2025-05-15 19:49:42 -07:00
async def send_totp_code (
2025-09-11 18:10:05 -07:00
data : TOTPCodeCreate ,
curr_org : Organization = Depends ( org_auth_service . get_current_org ) ,
2025-05-15 19:49:42 -07:00
) - > TOTPCode :
LOG . info (
2025-10-15 01:28:42 +08:00
" Saving OTP code " ,
2025-05-15 19:49:42 -07:00
organization_id = curr_org . organization_id ,
totp_identifier = data . totp_identifier ,
task_id = data . task_id ,
workflow_id = data . workflow_id ,
2025-07-17 21:36:18 -07:00
workflow_run_id = data . workflow_run_id ,
2025-05-15 19:49:42 -07:00
)
2025-05-26 13:28:20 -07:00
content = data . content . strip ( )
2025-10-15 01:28:42 +08:00
otp_value : OTPValue | None = OTPValue ( value = content , type = OTPType . TOTP )
2025-05-26 13:28:20 -07:00
# We assume the user is sending the code directly when the length of code is less than or equal to 10
if len ( content ) > 10 :
2025-10-15 01:28:42 +08:00
otp_value = await parse_otp_login ( content , curr_org . organization_id )
if not otp_value :
2025-05-26 13:28:20 -07:00
LOG . error (
2025-10-15 01:28:42 +08:00
" Failed to parse otp login " ,
2025-05-26 13:28:20 -07:00
totp_identifier = data . totp_identifier ,
task_id = data . task_id ,
workflow_id = data . workflow_id ,
workflow_run_id = data . workflow_run_id ,
content = data . content ,
)
2025-10-15 01:28:42 +08:00
raise HTTPException ( status_code = 400 , detail = " Failed to parse otp login " )
2025-10-14 16:24:14 +08:00
return await app . DATABASE . create_otp_code (
2025-05-15 19:49:42 -07:00
organization_id = curr_org . organization_id ,
totp_identifier = data . totp_identifier ,
content = data . content ,
2025-10-15 01:28:42 +08:00
code = otp_value . value ,
2025-05-15 19:49:42 -07:00
task_id = data . task_id ,
workflow_id = data . workflow_id ,
workflow_run_id = data . workflow_run_id ,
source = data . source ,
expired_at = data . expired_at ,
2025-10-15 01:28:42 +08:00
otp_type = otp_value . get_otp_type ( ) ,
2025-05-15 19:49:42 -07:00
)
2025-05-18 12:43:22 -07:00
@legacy_base_router.post ( " /credentials " )
@legacy_base_router.post ( " /credentials/ " , include_in_schema = False )
@base_router.post (
2025-05-15 19:49:42 -07:00
" /credentials " ,
response_model = CredentialResponse ,
2025-05-18 12:43:22 -07:00
status_code = 201 ,
summary = " Create credential " ,
description = " Creates a new credential for the current organization " ,
2025-05-15 19:49:42 -07:00
tags = [ " Credentials " ] ,
openapi_extra = {
2025-05-18 12:43:22 -07:00
" x-fern-sdk-method-name " : " create_credential " ,
2025-05-18 13:45:46 -07:00
" x-fern-examples " : [
{
" code-samples " : [
2025-10-28 17:43:19 -06:00
{ " sdk " : " python " , " code " : CREATE_CREDENTIAL_CODE_SAMPLE_PYTHON } ,
{ " sdk " : " python " , " code " : CREATE_CREDENTIAL_CODE_SAMPLE_CREDIT_CARD_PYTHON } ,
{ " sdk " : " typescript " , " code " : CREATE_CREDENTIAL_CODE_SAMPLE_TS } ,
{ " sdk " : " typescript " , " code " : CREATE_CREDENTIAL_CODE_SAMPLE_CREDIT_CARD_TS } ,
2025-05-18 13:45:46 -07:00
]
}
] ,
2025-05-15 19:49:42 -07:00
} ,
)
2025-05-18 13:45:46 -07:00
@base_router.post (
" /credentials/ " ,
response_model = CredentialResponse ,
status_code = 201 ,
include_in_schema = False ,
)
2025-05-18 12:43:22 -07:00
async def create_credential (
2025-10-08 14:39:15 -06:00
background_tasks : BackgroundTasks ,
2025-05-18 12:43:22 -07:00
data : CreateCredentialRequest = Body (
2025-05-15 19:49:42 -07:00
. . . ,
2025-05-18 12:43:22 -07:00
description = " The credential data to create " ,
example = {
" name " : " My Credential " ,
" credential_type " : " PASSWORD " ,
" credential " : { " username " : " user@example.com " , " password " : " securepassword123 " , " totp " : " JBSWY3DPEHPK3PXP " } ,
} ,
openapi_extra = { " x-fern-sdk-parameter-name " : " data " } ,
2025-05-15 19:49:42 -07:00
) ,
current_org : Organization = Depends ( org_auth_service . get_current_org ) ,
) - > CredentialResponse :
2025-10-10 10:10:18 -06:00
credential_service = await _get_credential_vault_service ( current_org . organization_id )
credential = await credential_service . create_credential ( organization_id = current_org . organization_id , data = data )
2025-05-15 19:49:42 -07:00
2025-10-10 10:10:18 -06:00
if credential . vault_type == CredentialVaultType . BITWARDEN :
# Early resyncing the Bitwarden vault
background_tasks . add_task ( fetch_credential_item_background , credential . item_id )
2025-10-08 14:39:15 -06:00
2025-05-18 12:43:22 -07:00
if data . credential_type == CredentialType . PASSWORD :
2025-05-15 19:49:42 -07:00
credential_response = PasswordCredentialResponse (
2025-05-18 12:43:22 -07:00
username = data . credential . username ,
2025-10-08 11:38:34 -07:00
totp_type = data . credential . totp_type if hasattr ( data . credential , " totp_type " ) else " none " ,
2025-05-15 19:49:42 -07:00
)
return CredentialResponse (
credential = credential_response ,
credential_id = credential . credential_id ,
2025-05-18 12:43:22 -07:00
credential_type = data . credential_type ,
name = data . name ,
2025-05-15 19:49:42 -07:00
)
2025-05-18 12:43:22 -07:00
elif data . credential_type == CredentialType . CREDIT_CARD :
2025-05-15 19:49:42 -07:00
credential_response = CreditCardCredentialResponse (
2025-05-18 12:43:22 -07:00
last_four = data . credential . card_number [ - 4 : ] ,
brand = data . credential . card_brand ,
2025-05-15 19:49:42 -07:00
)
return CredentialResponse (
credential = credential_response ,
credential_id = credential . credential_id ,
2025-05-18 12:43:22 -07:00
credential_type = data . credential_type ,
name = data . name ,
2025-05-15 19:49:42 -07:00
)
2025-10-09 11:39:01 -06:00
else :
raise HTTPException ( status_code = 400 , detail = f " Unsupported credential type: { data . credential_type } " )
2025-05-15 19:49:42 -07:00
@legacy_base_router.delete ( " /credentials/ {credential_id} " )
@legacy_base_router.delete ( " /credentials/ {credential_id} / " , include_in_schema = False )
@base_router.post (
" /credentials/ {credential_id} /delete " ,
status_code = 204 ,
summary = " Delete credential " ,
description = " Deletes a specific credential by its ID " ,
tags = [ " Credentials " ] ,
openapi_extra = {
" x-fern-sdk-method-name " : " delete_credential " ,
2025-10-28 17:43:19 -06:00
" x-fern-examples " : [
{
" code-samples " : [
{ " sdk " : " python " , " code " : DELETE_CREDENTIAL_CODE_SAMPLE_PYTHON } ,
{ " sdk " : " typescript " , " code " : DELETE_CREDENTIAL_CODE_SAMPLE_TS } ,
]
}
] ,
2025-05-15 19:49:42 -07:00
} ,
)
2025-05-18 13:45:46 -07:00
@base_router.post (
" /credentials/ {credential_id} /delete/ " ,
status_code = 204 ,
include_in_schema = False ,
)
2025-05-15 19:49:42 -07:00
async def delete_credential (
2025-10-14 20:25:22 -06:00
background_tasks : BackgroundTasks ,
2025-05-15 19:49:42 -07:00
credential_id : str = Path (
. . . ,
description = " The unique identifier of the credential to delete " ,
2025-06-13 22:58:55 -07:00
examples = [ " cred_1234567890 " ] ,
2025-05-15 19:49:42 -07:00
openapi_extra = { " x-fern-sdk-parameter-name " : " credential_id " } ,
) ,
current_org : Organization = Depends ( org_auth_service . get_current_org ) ,
) - > None :
credential = await app . DATABASE . get_credential (
credential_id = credential_id , organization_id = current_org . organization_id
)
if not credential :
raise HTTPException ( status_code = 404 , detail = f " Credential not found, credential_id= { credential_id } " )
2025-10-10 10:10:18 -06:00
vault_type = credential . vault_type or CredentialVaultType . BITWARDEN
credential_service = app . CREDENTIAL_VAULT_SERVICES . get ( vault_type )
if not credential_service :
raise HTTPException ( status_code = 400 , detail = " Unsupported credential storage type " )
await credential_service . delete_credential ( credential )
2025-05-15 19:49:42 -07:00
2025-10-14 20:25:22 -06:00
# Schedule background cleanup if the service implements it
background_tasks . add_task ( credential_service . post_delete_credential_item , credential . item_id )
2025-05-15 19:49:42 -07:00
return None
2025-05-18 12:43:22 -07:00
@legacy_base_router.get ( " /credentials/ {credential_id} " )
@legacy_base_router.get ( " /credentials/ {credential_id} / " , include_in_schema = False )
@base_router.get (
" /credentials/ {credential_id} " ,
2025-05-15 19:49:42 -07:00
response_model = CredentialResponse ,
2025-05-18 12:43:22 -07:00
summary = " Get credential by ID " ,
description = " Retrieves a specific credential by its ID " ,
2025-05-15 19:49:42 -07:00
tags = [ " Credentials " ] ,
openapi_extra = {
2025-05-18 12:43:22 -07:00
" x-fern-sdk-method-name " : " get_credential " ,
2025-10-28 17:43:19 -06:00
" x-fern-examples " : [
{
" code-samples " : [
{ " sdk " : " python " , " code " : GET_CREDENTIAL_CODE_SAMPLE_PYTHON } ,
{ " sdk " : " typescript " , " code " : GET_CREDENTIAL_CODE_SAMPLE_TS } ,
]
}
] ,
2025-05-15 19:49:42 -07:00
} ,
)
2025-05-18 13:45:46 -07:00
@base_router.get (
" /credentials/ {credential_id} / " ,
response_model = CredentialResponse ,
include_in_schema = False ,
)
2025-05-18 12:43:22 -07:00
async def get_credential (
credential_id : str = Path (
2025-05-15 19:49:42 -07:00
. . . ,
2025-05-18 12:43:22 -07:00
description = " The unique identifier of the credential " ,
2025-06-13 22:58:55 -07:00
examples = [ " cred_1234567890 " ] ,
2025-05-18 12:43:22 -07:00
openapi_extra = { " x-fern-sdk-parameter-name " : " credential_id " } ,
2025-05-15 19:49:42 -07:00
) ,
current_org : Organization = Depends ( org_auth_service . get_current_org ) ,
) - > CredentialResponse :
2025-10-10 10:10:18 -06:00
credential_service = await _get_credential_vault_service ( current_org . organization_id )
return await credential_service . get_credential ( current_org . organization_id , credential_id )
2025-05-18 12:43:22 -07:00
@legacy_base_router.get ( " /credentials " )
@legacy_base_router.get ( " /credentials/ " , include_in_schema = False )
@base_router.get (
" /credentials " ,
response_model = list [ CredentialResponse ] ,
summary = " Get all credentials " ,
description = " Retrieves a paginated list of credentials for the current organization " ,
tags = [ " Credentials " ] ,
openapi_extra = {
" x-fern-sdk-method-name " : " get_credentials " ,
2025-10-28 17:43:19 -06:00
" x-fern-examples " : [
{
" code-samples " : [
{ " sdk " : " python " , " code " : GET_CREDENTIALS_CODE_SAMPLE_PYTHON } ,
{ " sdk " : " typescript " , " code " : GET_CREDENTIALS_CODE_SAMPLE_TS } ,
]
}
] ,
2025-05-18 12:43:22 -07:00
} ,
)
2025-05-18 13:45:46 -07:00
@base_router.get (
" /credentials/ " ,
response_model = list [ CredentialResponse ] ,
include_in_schema = False ,
)
2025-05-18 12:43:22 -07:00
async def get_credentials (
current_org : Organization = Depends ( org_auth_service . get_current_org ) ,
page : int = Query (
1 ,
ge = 1 ,
description = " Page number for pagination " ,
2025-06-13 22:58:55 -07:00
examples = [ 1 ] ,
2025-05-18 12:43:22 -07:00
openapi_extra = { " x-fern-sdk-parameter-name " : " page " } ,
) ,
page_size : int = Query (
10 ,
ge = 1 ,
description = " Number of items per page " ,
2025-06-13 22:58:55 -07:00
examples = [ 10 ] ,
2025-05-18 12:43:22 -07:00
openapi_extra = { " x-fern-sdk-parameter-name " : " page_size " } ,
) ,
) - > list [ CredentialResponse ] :
2025-10-10 10:10:18 -06:00
credential_service = await _get_credential_vault_service ( current_org . organization_id )
return await credential_service . get_credentials ( current_org . organization_id , page , page_size )
2025-08-05 07:34:26 -07:00
@base_router.get (
2025-08-05 23:33:08 +08:00
" /credentials/onepassword/get " ,
2025-08-05 07:34:26 -07:00
response_model = CreateOnePasswordTokenResponse ,
summary = " Get OnePassword service account token " ,
description = " Retrieves the current OnePassword service account token for the organization. " ,
2025-08-14 09:08:47 -07:00
include_in_schema = False ,
2025-08-05 07:34:26 -07:00
)
@base_router.get (
2025-08-05 23:33:08 +08:00
" /credentials/onepassword/get/ " ,
2025-08-05 07:34:26 -07:00
response_model = CreateOnePasswordTokenResponse ,
include_in_schema = False ,
)
async def get_onepassword_token (
current_org : Organization = Depends ( org_auth_service . get_current_org ) ,
) - > CreateOnePasswordTokenResponse :
"""
Get the current OnePassword service account token for the organization .
"""
try :
auth_token = await app . DATABASE . get_valid_org_auth_token (
organization_id = current_org . organization_id ,
2025-09-26 16:35:47 -07:00
token_type = OrganizationAuthTokenType . onepassword_service_account . value ,
2025-08-05 07:34:26 -07:00
)
if not auth_token :
raise HTTPException (
status_code = 404 ,
detail = " No OnePassword service account token found for this organization " ,
)
return CreateOnePasswordTokenResponse ( token = auth_token )
except HTTPException :
raise
except Exception as e :
LOG . error (
" Failed to get OnePassword service account token " ,
organization_id = current_org . organization_id ,
error = str ( e ) ,
exc_info = True ,
)
raise HTTPException (
status_code = 500 ,
detail = f " Failed to get OnePassword service account token: { str ( e ) } " ,
)
@base_router.post (
2025-08-05 23:33:08 +08:00
" /credentials/onepassword/create " ,
2025-08-05 07:34:26 -07:00
response_model = CreateOnePasswordTokenResponse ,
summary = " Create or update OnePassword service account token " ,
description = " Creates or updates a OnePassword service account token for the current organization. Only one valid token is allowed per organization. " ,
2025-08-14 09:08:47 -07:00
include_in_schema = False ,
2025-08-05 07:34:26 -07:00
)
@base_router.post (
2025-08-05 23:33:08 +08:00
" /credentials/onepassword/create/ " ,
2025-08-05 07:34:26 -07:00
response_model = CreateOnePasswordTokenResponse ,
include_in_schema = False ,
)
async def update_onepassword_token (
2025-08-14 08:29:13 -07:00
data : CreateOnePasswordTokenRequest ,
2025-08-05 07:34:26 -07:00
current_org : Organization = Depends ( org_auth_service . get_current_org ) ,
) - > CreateOnePasswordTokenResponse :
"""
Create or update a OnePassword service account token for the current organization .
This endpoint ensures only one valid OnePassword token exists per organization .
If a valid token already exists , it will be invalidated before creating the new one .
"""
try :
# Invalidate any existing valid OnePassword tokens for this organization
await app . DATABASE . invalidate_org_auth_tokens (
organization_id = current_org . organization_id ,
token_type = OrganizationAuthTokenType . onepassword_service_account ,
)
# Create the new token
auth_token = await app . DATABASE . create_org_auth_token (
organization_id = current_org . organization_id ,
token_type = OrganizationAuthTokenType . onepassword_service_account ,
token = data . token ,
)
LOG . info (
" Created or updated OnePassword service account token " ,
organization_id = current_org . organization_id ,
token_id = auth_token . id ,
)
return CreateOnePasswordTokenResponse ( token = auth_token )
except Exception as e :
LOG . error (
" Failed to create or update OnePassword service account token " ,
organization_id = current_org . organization_id ,
error = str ( e ) ,
exc_info = True ,
)
raise HTTPException (
status_code = 500 ,
detail = f " Failed to create or update OnePassword service account token: { str ( e ) } " ,
)
2025-09-23 10:16:48 -06:00
@base_router.get (
" /credentials/azure_credential/get " ,
response_model = AzureClientSecretCredentialResponse ,
summary = " Get Azure Client Secret Credential " ,
description = " Retrieves the current Azure Client Secret Credential for the organization. " ,
include_in_schema = False ,
)
@base_router.get (
" /credentials/azure_credential/get/ " ,
response_model = AzureClientSecretCredentialResponse ,
include_in_schema = False ,
)
async def get_azure_client_secret_credential (
current_org : Organization = Depends ( org_auth_service . get_current_org ) ,
) - > AzureClientSecretCredentialResponse :
"""
Get the current Azure Client Secret Credential for the organization .
"""
try :
auth_token = await app . DATABASE . get_valid_org_auth_token (
organization_id = current_org . organization_id ,
2025-09-26 16:35:47 -07:00
token_type = OrganizationAuthTokenType . azure_client_secret_credential . value ,
2025-09-23 10:16:48 -06:00
)
if not auth_token :
raise HTTPException (
status_code = 404 ,
detail = " No Azure Client Secret Credential found for this organization " ,
)
return AzureClientSecretCredentialResponse ( token = auth_token )
except HTTPException :
raise
except Exception as e :
LOG . error (
" Failed to get Azure Client Secret Credential " ,
organization_id = current_org . organization_id ,
error = str ( e ) ,
exc_info = True ,
)
raise HTTPException (
status_code = 500 ,
detail = f " Failed to get Azure Client Secret Credential: { str ( e ) } " ,
)
@base_router.post (
" /credentials/azure_credential/create " ,
response_model = AzureClientSecretCredentialResponse ,
summary = " Create or update Azure Client Secret Credential " ,
description = " Creates or updates a Azure Client Secret Credential for the current organization. Only one valid record is allowed per organization. " ,
include_in_schema = False ,
)
@base_router.post (
" /credentials/azure_credential/create/ " ,
response_model = AzureClientSecretCredentialResponse ,
include_in_schema = False ,
)
async def update_azure_client_secret_credential (
request : CreateAzureClientSecretCredentialRequest ,
current_org : Organization = Depends ( org_auth_service . get_current_org ) ,
) - > AzureClientSecretCredentialResponse :
"""
Create or update an Azure Client Secret Credential for the current organization .
This endpoint ensures only one valid Azure Client Secret Credential exists per organization .
If a valid token already exists , it will be invalidated before creating the new one .
"""
try :
# Invalidate any existing valid Azure Client Secret Credential for this organization
await app . DATABASE . invalidate_org_auth_tokens (
organization_id = current_org . organization_id ,
token_type = OrganizationAuthTokenType . azure_client_secret_credential ,
)
# Create the new Azure token
auth_token = await app . DATABASE . create_org_auth_token (
organization_id = current_org . organization_id ,
token_type = OrganizationAuthTokenType . azure_client_secret_credential ,
token = request . credential ,
)
LOG . info (
" Created or updated Azure Client Secret Credential " ,
organization_id = current_org . organization_id ,
token_id = auth_token . id ,
)
return AzureClientSecretCredentialResponse ( token = auth_token )
except Exception as e :
LOG . error (
" Failed to create or update Azure Client Secret Credential " ,
organization_id = current_org . organization_id ,
error = str ( e ) ,
exc_info = True ,
)
raise HTTPException (
status_code = 500 ,
detail = f " Failed to create or update Azure Client Secret Credential: { str ( e ) } " ,
)
2025-10-10 10:10:18 -06:00
async def _get_credential_vault_service ( organization_id : str ) - > CredentialVaultService :
org_collection = await app . DATABASE . get_organization_bitwarden_collection ( organization_id )
if settings . CREDENTIAL_VAULT_TYPE == CredentialVaultType . BITWARDEN or org_collection :
return app . BITWARDEN_CREDENTIAL_VAULT_SERVICE
elif settings . CREDENTIAL_VAULT_TYPE == CredentialVaultType . AZURE_VAULT :
if not app . AZURE_CREDENTIAL_VAULT_SERVICE :
raise HTTPException ( status_code = 400 , detail = " Azure Vault credential is not supported " )
return app . AZURE_CREDENTIAL_VAULT_SERVICE
else :
raise HTTPException ( status_code = 400 , detail = " Credential storage not supported " )