mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-05-09 15:52:40 +02:00
feat: add Atlassian OAuth support for Jira and Confluence
- Introduced a shared schema for Atlassian OAuth 2.0 credentials, accommodating both Jira and Confluence. - Updated Jira connector routes to utilize the new AtlassianAuthCredentialsBase for handling OAuth tokens. - Enhanced configuration to include new environment variables for Jira OAuth integration. - Refactored token handling in Jira indexing logic to support the new shared credential structure.
This commit is contained in:
parent
982b9ceb76
commit
bf8c3bfcf7
4 changed files with 27 additions and 7 deletions
|
|
@ -95,6 +95,11 @@ class Config:
|
||||||
NOTION_CLIENT_SECRET = os.getenv("NOTION_CLIENT_SECRET")
|
NOTION_CLIENT_SECRET = os.getenv("NOTION_CLIENT_SECRET")
|
||||||
NOTION_REDIRECT_URI = os.getenv("NOTION_REDIRECT_URI")
|
NOTION_REDIRECT_URI = os.getenv("NOTION_REDIRECT_URI")
|
||||||
|
|
||||||
|
# Jira OAuth
|
||||||
|
JIRA_CLIENT_ID = os.getenv("JIRA_CLIENT_ID")
|
||||||
|
JIRA_CLIENT_SECRET = os.getenv("JIRA_CLIENT_SECRET")
|
||||||
|
JIRA_REDIRECT_URI = os.getenv("JIRA_REDIRECT_URI")
|
||||||
|
|
||||||
# Linear OAuth
|
# Linear OAuth
|
||||||
LINEAR_CLIENT_ID = os.getenv("LINEAR_CLIENT_ID")
|
LINEAR_CLIENT_ID = os.getenv("LINEAR_CLIENT_ID")
|
||||||
LINEAR_CLIENT_SECRET = os.getenv("LINEAR_CLIENT_SECRET")
|
LINEAR_CLIENT_SECRET = os.getenv("LINEAR_CLIENT_SECRET")
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ from app.db import (
|
||||||
User,
|
User,
|
||||||
get_async_session,
|
get_async_session,
|
||||||
)
|
)
|
||||||
from app.schemas.jira_auth_credentials import JiraAuthCredentialsBase
|
from app.schemas.atlassian_auth_credentials import AtlassianAuthCredentialsBase
|
||||||
from app.users import current_active_user
|
from app.users import current_active_user
|
||||||
from app.utils.oauth_security import OAuthStateManager, TokenEncryption
|
from app.utils.oauth_security import OAuthStateManager, TokenEncryption
|
||||||
|
|
||||||
|
|
@ -392,7 +392,7 @@ async def refresh_jira_token(
|
||||||
try:
|
try:
|
||||||
logger.info(f"Refreshing Jira token for connector {connector.id}")
|
logger.info(f"Refreshing Jira token for connector {connector.id}")
|
||||||
|
|
||||||
credentials = JiraAuthCredentialsBase.from_dict(connector.config)
|
credentials = AtlassianAuthCredentialsBase.from_dict(connector.config)
|
||||||
|
|
||||||
# Decrypt tokens if they are encrypted
|
# Decrypt tokens if they are encrypted
|
||||||
token_encryption = get_token_encryption()
|
token_encryption = get_token_encryption()
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,23 @@
|
||||||
|
"""
|
||||||
|
Atlassian OAuth 2.0 Authentication Credentials Schema.
|
||||||
|
|
||||||
|
Shared schema for both Jira and Confluence OAuth credentials.
|
||||||
|
Both products use the same Atlassian OAuth 2.0 (3LO) flow and token structure.
|
||||||
|
"""
|
||||||
|
|
||||||
from datetime import UTC, datetime
|
from datetime import UTC, datetime
|
||||||
|
|
||||||
from pydantic import BaseModel, field_validator
|
from pydantic import BaseModel, field_validator
|
||||||
|
|
||||||
|
|
||||||
class JiraAuthCredentialsBase(BaseModel):
|
class AtlassianAuthCredentialsBase(BaseModel):
|
||||||
|
"""
|
||||||
|
Base model for Atlassian OAuth 2.0 credentials.
|
||||||
|
|
||||||
|
Used for both Jira and Confluence connectors since they share
|
||||||
|
the same Atlassian OAuth infrastructure and token structure.
|
||||||
|
"""
|
||||||
|
|
||||||
access_token: str
|
access_token: str
|
||||||
refresh_token: str | None = None
|
refresh_token: str | None = None
|
||||||
token_type: str = "Bearer"
|
token_type: str = "Bearer"
|
||||||
|
|
@ -39,7 +53,7 @@ class JiraAuthCredentialsBase(BaseModel):
|
||||||
}
|
}
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_dict(cls, data: dict) -> "JiraAuthCredentialsBase":
|
def from_dict(cls, data: dict) -> "AtlassianAuthCredentialsBase":
|
||||||
"""Create credentials from dictionary."""
|
"""Create credentials from dictionary."""
|
||||||
expires_at = None
|
expires_at = None
|
||||||
if data.get("expires_at"):
|
if data.get("expires_at"):
|
||||||
|
|
@ -70,3 +84,4 @@ class JiraAuthCredentialsBase(BaseModel):
|
||||||
if isinstance(v, datetime):
|
if isinstance(v, datetime):
|
||||||
return v if v.tzinfo else v.replace(tzinfo=UTC)
|
return v if v.tzinfo else v.replace(tzinfo=UTC)
|
||||||
return v
|
return v
|
||||||
|
|
||||||
|
|
@ -131,8 +131,8 @@ async def index_jira_issues(
|
||||||
return 0, f"Failed to decrypt Jira tokens: {e!s}"
|
return 0, f"Failed to decrypt Jira tokens: {e!s}"
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from app.schemas.jira_auth_credentials import JiraAuthCredentialsBase
|
from app.schemas.atlassian_auth_credentials import AtlassianAuthCredentialsBase
|
||||||
credentials = JiraAuthCredentialsBase.from_dict(config_data)
|
credentials = AtlassianAuthCredentialsBase.from_dict(config_data)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
await task_logger.log_task_failure(
|
await task_logger.log_task_failure(
|
||||||
log_entry,
|
log_entry,
|
||||||
|
|
@ -160,7 +160,7 @@ async def index_jira_issues(
|
||||||
config_data["access_token"] = token_encryption.decrypt_token(
|
config_data["access_token"] = token_encryption.decrypt_token(
|
||||||
config_data["access_token"]
|
config_data["access_token"]
|
||||||
)
|
)
|
||||||
credentials = JiraAuthCredentialsBase.from_dict(config_data)
|
credentials = AtlassianAuthCredentialsBase.from_dict(config_data)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
await task_logger.log_task_failure(
|
await task_logger.log_task_failure(
|
||||||
log_entry,
|
log_entry,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue