mirror of
https://github.com/openswarm-ai/openswarm.git
synced 2026-09-11 12:17:45 +02:00
[Haik]: abstracted and refactored the oath providers so its easier to add on to.
This commit is contained in:
@@ -0,0 +1,21 @@
|
||||
from backend.apps.tools.oauth.OAUTH_PROVIDERS.OAuthProvider import OAuthProvider
|
||||
from backend.apps.tools.oauth.OAUTH_PROVIDERS.providers.GOOGLE_PROVIDER import GOOGLE_PROVIDER
|
||||
from backend.apps.tools.oauth.OAUTH_PROVIDERS.providers.GITHUB_PROVIDER import GITHUB_PROVIDER
|
||||
from backend.apps.tools.oauth.OAUTH_PROVIDERS.providers.SLACK_PROVIDER import SLACK_PROVIDER
|
||||
from backend.apps.tools.oauth.OAUTH_PROVIDERS.providers.NOTION_PROVIDER import NOTION_PROVIDER
|
||||
from backend.apps.tools.oauth.OAUTH_PROVIDERS.providers.SPOTIFY_PROVIDER import SPOTIFY_PROVIDER
|
||||
from backend.apps.tools.oauth.OAUTH_PROVIDERS.providers.FIGMA_PROVIDER import FIGMA_PROVIDER
|
||||
from backend.apps.tools.oauth.OAUTH_PROVIDERS.providers.AIRTABLE_PROVIDER import AIRTABLE_PROVIDER
|
||||
from backend.apps.tools.oauth.OAUTH_PROVIDERS.providers.HUBSPOT_PROVIDER import HUBSPOT_PROVIDER
|
||||
|
||||
|
||||
OAUTH_PROVIDERS: dict[str, OAuthProvider] = {
|
||||
"google": GOOGLE_PROVIDER,
|
||||
"github": GITHUB_PROVIDER,
|
||||
"slack": SLACK_PROVIDER,
|
||||
"notion": NOTION_PROVIDER,
|
||||
"spotify": SPOTIFY_PROVIDER,
|
||||
"figma": FIGMA_PROVIDER,
|
||||
"airtable": AIRTABLE_PROVIDER,
|
||||
"hubspot": HUBSPOT_PROVIDER,
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
from pydantic import BaseModel, Field
|
||||
from typing import List, Optional, Dict
|
||||
from typing_extensions import Literal
|
||||
|
||||
class OAuthProvider(BaseModel):
|
||||
auth_url: str
|
||||
token_url: str
|
||||
scopes: List[str]
|
||||
userinfo_url: Optional[str] = None
|
||||
userinfo_field: str
|
||||
client_id_env: str
|
||||
client_secret_env: str
|
||||
token_env_mapping: Dict[str, str]
|
||||
extra_auth_params: Dict[str, str] = Field(default_factory=dict)
|
||||
revoke_url: Optional[str] = None
|
||||
token_response_path: Optional[str] = None
|
||||
token_auth_method: Literal["form", "basic", "basic_json"] # newly required
|
||||
pkce_required: bool # newly required
|
||||
env_value_transform: Optional[str] = None
|
||||
extra_token_fields: Dict[str, str] = Field(default_factory=dict)
|
||||
@@ -0,0 +1,24 @@
|
||||
from backend.apps.tools.oauth.OAUTH_PROVIDERS.OAuthProvider import OAuthProvider
|
||||
import os
|
||||
|
||||
# TODO: wtf is this, bruh we gotta remove this shit asap r u fr rn. Unacceptable.
|
||||
os.environ.setdefault("AIRTABLE_CLIENT_ID", "0699038b-a3a4-46b2-8fa6-690eb76fadfa")
|
||||
os.environ.setdefault("AIRTABLE_CLIENT_SECRET", "187fa83c8bab8ebcd11b8f226d75e7a1f14a8174ac0494463c1a53e66a3036d0")
|
||||
|
||||
AIRTABLE_PROVIDER: OAuthProvider = OAuthProvider(
|
||||
auth_url="https://airtable.com/oauth2/v1/authorize",
|
||||
token_url="https://airtable.com/oauth2/v1/token",
|
||||
scopes=[
|
||||
"data.records:read", "data.records:write",
|
||||
"data.recordComments:read", "data.recordComments:write",
|
||||
"schema.bases:read", "schema.bases:write",
|
||||
"user.email:read", "webhook:manage",
|
||||
],
|
||||
userinfo_url="https://api.airtable.com/v0/meta/whoami",
|
||||
userinfo_field="email",
|
||||
client_id_env="AIRTABLE_CLIENT_ID",
|
||||
client_secret_env="AIRTABLE_CLIENT_SECRET",
|
||||
token_env_mapping={"access_token": "AIRTABLE_API_KEY"},
|
||||
pkce_required=True,
|
||||
token_auth_method="basic",
|
||||
)
|
||||
@@ -0,0 +1,23 @@
|
||||
from backend.apps.tools.oauth.OAUTH_PROVIDERS.OAuthProvider import OAuthProvider
|
||||
import os
|
||||
|
||||
# TODO: wtf is this, bruh we gotta remove this shit asap r u fr rn. Unacceptable.
|
||||
os.environ.setdefault("FIGMA_CLIENT_ID", "q6WduT7UuPaO6lM88v6ddN")
|
||||
os.environ.setdefault("FIGMA_CLIENT_SECRET", "dhNZdbEuyEWC15cKLwWpqTclyOSplD")
|
||||
|
||||
FIGMA_PROVIDER: OAuthProvider = OAuthProvider(
|
||||
auth_url="https://www.figma.com/oauth",
|
||||
token_url="https://api.figma.com/v1/oauth/token",
|
||||
scopes=[
|
||||
"current_user:read", "file_content:read", "file_metadata:read",
|
||||
"file_comments:read", "file_comments:write",
|
||||
"file_versions:read", "file_variables:read",
|
||||
],
|
||||
userinfo_url="https://api.figma.com/v1/me",
|
||||
userinfo_field="email",
|
||||
client_id_env="FIGMA_CLIENT_ID",
|
||||
client_secret_env="FIGMA_CLIENT_SECRET",
|
||||
token_env_mapping={"access_token": "FIGMA_API_KEY"},
|
||||
token_auth_method="form",
|
||||
pkce_required=False,
|
||||
)
|
||||
@@ -0,0 +1,19 @@
|
||||
from backend.apps.tools.oauth.OAUTH_PROVIDERS.OAuthProvider import OAuthProvider
|
||||
import os
|
||||
|
||||
# TODO: wtf is this, bruh we gotta remove this shit asap r u fr rn. Unacceptable.
|
||||
os.environ.setdefault("GITHUB_OAUTH_CLIENT_ID", "Ov23liDcwNJaKMjXY2jI")
|
||||
os.environ.setdefault("GITHUB_OAUTH_CLIENT_SECRET", "b25fe39409896aad3fd5155f032e9868440002f8")
|
||||
|
||||
GITHUB_PROVIDER: OAuthProvider = OAuthProvider(
|
||||
auth_url="https://github.com/login/oauth/authorize",
|
||||
token_url="https://github.com/login/oauth/access_token",
|
||||
scopes=["repo", "read:user", "user:email"],
|
||||
userinfo_url="https://api.github.com/user",
|
||||
userinfo_field="login",
|
||||
client_id_env="GITHUB_OAUTH_CLIENT_ID",
|
||||
client_secret_env="GITHUB_OAUTH_CLIENT_SECRET",
|
||||
token_env_mapping={"access_token": "GITHUB_PERSONAL_ACCESS_TOKEN"},
|
||||
token_auth_method="form",
|
||||
pkce_required=False,
|
||||
)
|
||||
@@ -0,0 +1,32 @@
|
||||
from backend.apps.tools.oauth.OAUTH_PROVIDERS.OAuthProvider import OAuthProvider
|
||||
import os
|
||||
|
||||
# TODO: wtf is this, bruh we gotta remove this shit asap r u fr rn. Unacceptable.
|
||||
os.environ.setdefault("GOOGLE_OAUTH_CLIENT_ID", "6741219524-8vpt07arcc5rvkdb4j1b6v9g53469ugq.apps.googleusercontent.com")
|
||||
os.environ.setdefault("GOOGLE_OAUTH_CLIENT_SECRET", "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")
|
||||
|
||||
GOOGLE_PROVIDER: OAuthProvider = OAuthProvider(
|
||||
auth_url="https://accounts.google.com/o/oauth2/v2/auth",
|
||||
token_url="https://oauth2.googleapis.com/token",
|
||||
scopes=[
|
||||
"openid",
|
||||
"https://www.googleapis.com/auth/userinfo.email",
|
||||
"https://www.googleapis.com/auth/gmail.modify",
|
||||
"https://www.googleapis.com/auth/calendar",
|
||||
"https://www.googleapis.com/auth/drive",
|
||||
"https://www.googleapis.com/auth/contacts.readonly",
|
||||
],
|
||||
userinfo_url="https://www.googleapis.com/oauth2/v2/userinfo",
|
||||
userinfo_field="email",
|
||||
client_id_env="GOOGLE_OAUTH_CLIENT_ID",
|
||||
client_secret_env="GOOGLE_OAUTH_CLIENT_SECRET",
|
||||
token_env_mapping={
|
||||
"access_token": "OAUTH_ACCESS_TOKEN",
|
||||
"refresh_token": "GOOGLE_WORKSPACE_REFRESH_TOKEN",
|
||||
"_client_id": "GOOGLE_WORKSPACE_CLIENT_ID",
|
||||
"_client_secret": "GOOGLE_WORKSPACE_CLIENT_SECRET",
|
||||
},
|
||||
extra_auth_params={"access_type": "offline", "prompt": "consent"},
|
||||
pkce_required=False,
|
||||
token_auth_method="form",
|
||||
)
|
||||
@@ -0,0 +1,22 @@
|
||||
from backend.apps.tools.oauth.OAUTH_PROVIDERS.OAuthProvider import OAuthProvider
|
||||
import os
|
||||
|
||||
# TODO: wtf is this, bruh we gotta remove this shit asap r u fr rn. Unacceptable.
|
||||
os.environ.setdefault("HUBSPOT_CLIENT_ID", "6f4a1d4c-6a2f-4336-9b65-2cd84e218ff6")
|
||||
os.environ.setdefault("HUBSPOT_CLIENT_SECRET", "5747b5de-0800-4c35-a2da-e0655ee7ea37")
|
||||
|
||||
HUBSPOT_PROVIDER: OAuthProvider = OAuthProvider(
|
||||
auth_url="https://mcp-na2.hubspot.com/oauth/authorize/user",
|
||||
token_url="https://api.hubapi.com/oauth/v1/token",
|
||||
scopes=[],
|
||||
userinfo_url=None,
|
||||
userinfo_field="user",
|
||||
client_id_env="HUBSPOT_CLIENT_ID",
|
||||
client_secret_env="HUBSPOT_CLIENT_SECRET",
|
||||
token_env_mapping={
|
||||
"access_token": "PRIVATE_APP_ACCESS_TOKEN",
|
||||
"refresh_token": "HUBSPOT_REFRESH_TOKEN",
|
||||
},
|
||||
token_auth_method="form",
|
||||
pkce_required=True,
|
||||
)
|
||||
@@ -0,0 +1,18 @@
|
||||
from backend.apps.tools.oauth.OAUTH_PROVIDERS.OAuthProvider import OAuthProvider
|
||||
|
||||
# TODO: why doesn't notion have any client id or secret?
|
||||
|
||||
NOTION_PROVIDER: OAuthProvider = OAuthProvider(
|
||||
auth_url="https://api.notion.com/v1/oauth/authorize",
|
||||
token_url="https://api.notion.com/v1/oauth/token",
|
||||
scopes=[],
|
||||
userinfo_url=None,
|
||||
userinfo_field="owner",
|
||||
client_id_env="NOTION_OAUTH_CLIENT_ID",
|
||||
client_secret_env="NOTION_OAUTH_CLIENT_SECRET",
|
||||
token_env_mapping={"access_token": "OPENAPI_MCP_HEADERS"},
|
||||
extra_auth_params={"owner": "user"},
|
||||
token_auth_method="basic_json",
|
||||
pkce_required=False,
|
||||
env_value_transform="notion_headers",
|
||||
)
|
||||
@@ -0,0 +1,26 @@
|
||||
from backend.apps.tools.oauth.OAUTH_PROVIDERS.OAuthProvider import OAuthProvider
|
||||
import os
|
||||
|
||||
# TODO: wtf is this, bruh we gotta remove this shit asap r u fr rn. Unacceptable.
|
||||
os.environ.setdefault("SLACK_CLIENT_ID", "10795695056323.10799999254534")
|
||||
os.environ.setdefault("SLACK_CLIENT_SECRET", "d3a85a286bb0205157d7e4963502a91d")
|
||||
|
||||
SLACK_PROVIDER: OAuthProvider = OAuthProvider(
|
||||
auth_url="https://slack.com/oauth/v2/authorize",
|
||||
token_url="https://slack.com/api/oauth.v2.access",
|
||||
scopes=[
|
||||
"channels:read", "channels:history", "chat:write",
|
||||
"groups:read", "groups:history", "im:read", "im:history",
|
||||
"mpim:read", "mpim:history", "users:read", "users:read.email",
|
||||
"team:read", "reactions:read", "reactions:write",
|
||||
"files:read", "files:write",
|
||||
],
|
||||
userinfo_url="https://slack.com/api/auth.test",
|
||||
userinfo_field="user",
|
||||
client_id_env="SLACK_CLIENT_ID",
|
||||
client_secret_env="SLACK_CLIENT_SECRET",
|
||||
token_env_mapping={"access_token": "SLACK_BOT_TOKEN"},
|
||||
extra_token_fields={"team.id": "SLACK_TEAM_ID"},
|
||||
token_auth_method="form",
|
||||
pkce_required=False,
|
||||
)
|
||||
@@ -0,0 +1,27 @@
|
||||
from backend.apps.tools.oauth.OAUTH_PROVIDERS.OAuthProvider import OAuthProvider
|
||||
|
||||
# TODO: why doesn't spotify have any client id or secret?
|
||||
|
||||
SPOTIFY_PROVIDER: OAuthProvider = OAuthProvider(
|
||||
auth_url="https://accounts.spotify.com/authorize",
|
||||
token_url="https://accounts.spotify.com/api/token",
|
||||
scopes=[
|
||||
"user-read-playback-state", "user-modify-playback-state",
|
||||
"user-read-currently-playing", "playlist-read-private",
|
||||
"playlist-modify-public", "playlist-modify-private",
|
||||
"user-library-read", "user-library-modify",
|
||||
"user-read-recently-played", "user-top-read",
|
||||
],
|
||||
userinfo_url="https://api.spotify.com/v1/me",
|
||||
userinfo_field="display_name",
|
||||
client_id_env="SPOTIFY_CLIENT_ID",
|
||||
client_secret_env="SPOTIFY_CLIENT_SECRET",
|
||||
token_env_mapping={
|
||||
"access_token": "SPOTIFY_ACCESS_TOKEN",
|
||||
"refresh_token": "SPOTIFY_REFRESH_TOKEN",
|
||||
"_client_id": "SPOTIFY_CLIENT_ID",
|
||||
"_client_secret": "SPOTIFY_CLIENT_SECRET",
|
||||
},
|
||||
token_auth_method="basic",
|
||||
pkce_required=False,
|
||||
)
|
||||
@@ -17,11 +17,12 @@ import httpx
|
||||
from fastapi import HTTPException, Query
|
||||
from fastapi.responses import HTMLResponse
|
||||
|
||||
from backend.apps.tools.oauth.oauth_providers import resolve_oauth_provider
|
||||
from backend.apps.tools.oauth.OAUTH_PROVIDERS.OAUTH_PROVIDERS import OAUTH_PROVIDERS
|
||||
from backend.core.db.PydanticStore import PydanticStore
|
||||
from backend.apps.tools.shared_utils.ToolDefinition import ToolDefinition
|
||||
from backend.ports import BACKEND_DEV_PORT
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
_pending_oauth: dict[str, str] = {}
|
||||
@@ -49,7 +50,7 @@ async def oauth_callback(code: str = Query(...), state: str = Query("")) -> HTML
|
||||
|
||||
store = _get_store()
|
||||
tool = store.load(tool_id)
|
||||
provider = resolve_oauth_provider(tool.oauth_provider)
|
||||
provider = OAUTH_PROVIDERS[tool.oauth_provider]
|
||||
|
||||
client_id = os.environ.get(provider.client_id_env, "")
|
||||
client_secret = os.environ.get(provider.client_secret_env, "")
|
||||
@@ -151,7 +152,7 @@ async def oauth_callback(code: str = Query(...), state: str = Query("")) -> HTML
|
||||
async def oauth_start(tool_id: str) -> dict:
|
||||
store = _get_store()
|
||||
tool = store.load(tool_id)
|
||||
provider = resolve_oauth_provider(tool.oauth_provider)
|
||||
provider = OAUTH_PROVIDERS[tool.oauth_provider]
|
||||
|
||||
client_id = os.environ.get(provider.client_id_env, "")
|
||||
if not client_id:
|
||||
@@ -193,7 +194,7 @@ async def oauth_disconnect(tool_id: str) -> dict:
|
||||
access_token = tool.oauth_tokens.get("access_token")
|
||||
|
||||
if access_token:
|
||||
provider = resolve_oauth_provider(tool.oauth_provider)
|
||||
provider = OAUTH_PROVIDERS[tool.oauth_provider]
|
||||
revoke_url = provider.revoke_url or "https://oauth2.googleapis.com/revoke"
|
||||
try:
|
||||
async with httpx.AsyncClient(timeout=10.0) as client:
|
||||
@@ -226,7 +227,7 @@ async def refresh_oauth_token(tool: ToolDefinition) -> Optional[str]:
|
||||
if time.time() < expiry - 60:
|
||||
return tool.oauth_tokens.get("access_token")
|
||||
|
||||
provider = resolve_oauth_provider(tool.oauth_provider)
|
||||
provider = OAUTH_PROVIDERS[tool.oauth_provider]
|
||||
client_id = os.environ.get(provider.client_id_env, "")
|
||||
client_secret = os.environ.get(provider.client_secret_env, "")
|
||||
if not client_id or not client_secret:
|
||||
|
||||
@@ -1,181 +0,0 @@
|
||||
"""OAuth provider definitions — pure data, no route handlers."""
|
||||
|
||||
import os
|
||||
from dataclasses import dataclass, field
|
||||
|
||||
|
||||
# TODO: wtf is this, bruh we gotta remove this shit asap r u fr rn. Unacceptable.
|
||||
os.environ.setdefault("GOOGLE_OAUTH_CLIENT_ID", "6741219524-8vpt07arcc5rvkdb4j1b6v9g53469ugq.apps.googleusercontent.com")
|
||||
os.environ.setdefault("GOOGLE_OAUTH_CLIENT_SECRET", "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")
|
||||
os.environ.setdefault("GITHUB_OAUTH_CLIENT_ID", "Ov23liDcwNJaKMjXY2jI")
|
||||
os.environ.setdefault("GITHUB_OAUTH_CLIENT_SECRET", "b25fe39409896aad3fd5155f032e9868440002f8")
|
||||
os.environ.setdefault("SLACK_CLIENT_ID", "10795695056323.10799999254534")
|
||||
os.environ.setdefault("SLACK_CLIENT_SECRET", "d3a85a286bb0205157d7e4963502a91d")
|
||||
os.environ.setdefault("FIGMA_CLIENT_ID", "q6WduT7UuPaO6lM88v6ddN")
|
||||
os.environ.setdefault("FIGMA_CLIENT_SECRET", "dhNZdbEuyEWC15cKLwWpqTclyOSplD")
|
||||
os.environ.setdefault("AIRTABLE_CLIENT_ID", "0699038b-a3a4-46b2-8fa6-690eb76fadfa")
|
||||
os.environ.setdefault("AIRTABLE_CLIENT_SECRET", "187fa83c8bab8ebcd11b8f226d75e7a1f14a8174ac0494463c1a53e66a3036d0")
|
||||
os.environ.setdefault("HUBSPOT_CLIENT_ID", "6f4a1d4c-6a2f-4336-9b65-2cd84e218ff6")
|
||||
os.environ.setdefault("HUBSPOT_CLIENT_SECRET", "5747b5de-0800-4c35-a2da-e0655ee7ea37")
|
||||
|
||||
|
||||
@dataclass
|
||||
class OAuthProvider:
|
||||
auth_url: str
|
||||
token_url: str
|
||||
scopes: list[str]
|
||||
userinfo_url: str | None
|
||||
userinfo_field: str
|
||||
client_id_env: str
|
||||
client_secret_env: str
|
||||
token_env_mapping: dict[str, str]
|
||||
extra_auth_params: dict[str, str] = field(default_factory=dict)
|
||||
revoke_url: str | None = None
|
||||
token_response_path: str | None = None
|
||||
token_auth_method: str = "form"
|
||||
pkce_required: bool = False
|
||||
env_value_transform: str | None = None
|
||||
extra_token_fields: dict[str, str] = field(default_factory=dict)
|
||||
|
||||
|
||||
OAUTH_PROVIDERS: dict[str, OAuthProvider] = {
|
||||
"google": OAuthProvider(
|
||||
auth_url="https://accounts.google.com/o/oauth2/v2/auth",
|
||||
token_url="https://oauth2.googleapis.com/token",
|
||||
scopes=[
|
||||
"openid",
|
||||
"https://www.googleapis.com/auth/userinfo.email",
|
||||
"https://www.googleapis.com/auth/gmail.modify",
|
||||
"https://www.googleapis.com/auth/calendar",
|
||||
"https://www.googleapis.com/auth/drive",
|
||||
"https://www.googleapis.com/auth/contacts.readonly",
|
||||
],
|
||||
userinfo_url="https://www.googleapis.com/oauth2/v2/userinfo",
|
||||
userinfo_field="email",
|
||||
client_id_env="GOOGLE_OAUTH_CLIENT_ID",
|
||||
client_secret_env="GOOGLE_OAUTH_CLIENT_SECRET",
|
||||
token_env_mapping={
|
||||
"access_token": "OAUTH_ACCESS_TOKEN",
|
||||
"refresh_token": "GOOGLE_WORKSPACE_REFRESH_TOKEN",
|
||||
"_client_id": "GOOGLE_WORKSPACE_CLIENT_ID",
|
||||
"_client_secret": "GOOGLE_WORKSPACE_CLIENT_SECRET",
|
||||
},
|
||||
extra_auth_params={"access_type": "offline", "prompt": "consent"},
|
||||
),
|
||||
"github": OAuthProvider(
|
||||
auth_url="https://github.com/login/oauth/authorize",
|
||||
token_url="https://github.com/login/oauth/access_token",
|
||||
scopes=["repo", "read:user", "user:email"],
|
||||
userinfo_url="https://api.github.com/user",
|
||||
userinfo_field="login",
|
||||
client_id_env="GITHUB_OAUTH_CLIENT_ID",
|
||||
client_secret_env="GITHUB_OAUTH_CLIENT_SECRET",
|
||||
token_env_mapping={"access_token": "GITHUB_PERSONAL_ACCESS_TOKEN"},
|
||||
),
|
||||
"slack": OAuthProvider(
|
||||
auth_url="https://slack.com/oauth/v2/authorize",
|
||||
token_url="https://slack.com/api/oauth.v2.access",
|
||||
scopes=[
|
||||
"channels:read", "channels:history", "chat:write",
|
||||
"groups:read", "groups:history", "im:read", "im:history",
|
||||
"mpim:read", "mpim:history", "users:read", "users:read.email",
|
||||
"team:read", "reactions:read", "reactions:write",
|
||||
"files:read", "files:write",
|
||||
],
|
||||
userinfo_url="https://slack.com/api/auth.test",
|
||||
userinfo_field="user",
|
||||
client_id_env="SLACK_CLIENT_ID",
|
||||
client_secret_env="SLACK_CLIENT_SECRET",
|
||||
token_env_mapping={"access_token": "SLACK_BOT_TOKEN"},
|
||||
extra_token_fields={"team.id": "SLACK_TEAM_ID"},
|
||||
),
|
||||
"notion": OAuthProvider(
|
||||
auth_url="https://api.notion.com/v1/oauth/authorize",
|
||||
token_url="https://api.notion.com/v1/oauth/token",
|
||||
scopes=[],
|
||||
userinfo_url=None,
|
||||
userinfo_field="owner",
|
||||
client_id_env="NOTION_OAUTH_CLIENT_ID",
|
||||
client_secret_env="NOTION_OAUTH_CLIENT_SECRET",
|
||||
token_env_mapping={"access_token": "OPENAPI_MCP_HEADERS"},
|
||||
extra_auth_params={"owner": "user"},
|
||||
token_auth_method="basic_json",
|
||||
env_value_transform="notion_headers",
|
||||
),
|
||||
"spotify": OAuthProvider(
|
||||
auth_url="https://accounts.spotify.com/authorize",
|
||||
token_url="https://accounts.spotify.com/api/token",
|
||||
scopes=[
|
||||
"user-read-playback-state", "user-modify-playback-state",
|
||||
"user-read-currently-playing", "playlist-read-private",
|
||||
"playlist-modify-public", "playlist-modify-private",
|
||||
"user-library-read", "user-library-modify",
|
||||
"user-read-recently-played", "user-top-read",
|
||||
],
|
||||
userinfo_url="https://api.spotify.com/v1/me",
|
||||
userinfo_field="display_name",
|
||||
client_id_env="SPOTIFY_CLIENT_ID",
|
||||
client_secret_env="SPOTIFY_CLIENT_SECRET",
|
||||
token_env_mapping={
|
||||
"access_token": "SPOTIFY_ACCESS_TOKEN",
|
||||
"refresh_token": "SPOTIFY_REFRESH_TOKEN",
|
||||
"_client_id": "SPOTIFY_CLIENT_ID",
|
||||
"_client_secret": "SPOTIFY_CLIENT_SECRET",
|
||||
},
|
||||
token_auth_method="basic",
|
||||
),
|
||||
"figma": OAuthProvider(
|
||||
auth_url="https://www.figma.com/oauth",
|
||||
token_url="https://api.figma.com/v1/oauth/token",
|
||||
scopes=[
|
||||
"current_user:read", "file_content:read", "file_metadata:read",
|
||||
"file_comments:read", "file_comments:write",
|
||||
"file_versions:read", "file_variables:read",
|
||||
],
|
||||
userinfo_url="https://api.figma.com/v1/me",
|
||||
userinfo_field="email",
|
||||
client_id_env="FIGMA_CLIENT_ID",
|
||||
client_secret_env="FIGMA_CLIENT_SECRET",
|
||||
token_env_mapping={"access_token": "FIGMA_API_KEY"},
|
||||
),
|
||||
"airtable": OAuthProvider(
|
||||
auth_url="https://airtable.com/oauth2/v1/authorize",
|
||||
token_url="https://airtable.com/oauth2/v1/token",
|
||||
scopes=[
|
||||
"data.records:read", "data.records:write",
|
||||
"data.recordComments:read", "data.recordComments:write",
|
||||
"schema.bases:read", "schema.bases:write",
|
||||
"user.email:read", "webhook:manage",
|
||||
],
|
||||
userinfo_url="https://api.airtable.com/v0/meta/whoami",
|
||||
userinfo_field="email",
|
||||
client_id_env="AIRTABLE_CLIENT_ID",
|
||||
client_secret_env="AIRTABLE_CLIENT_SECRET",
|
||||
token_env_mapping={"access_token": "AIRTABLE_API_KEY"},
|
||||
pkce_required=True,
|
||||
token_auth_method="basic",
|
||||
),
|
||||
"hubspot": OAuthProvider(
|
||||
auth_url="https://mcp-na2.hubspot.com/oauth/authorize/user",
|
||||
token_url="https://api.hubapi.com/oauth/v1/token",
|
||||
scopes=[],
|
||||
userinfo_url=None,
|
||||
userinfo_field="user",
|
||||
client_id_env="HUBSPOT_CLIENT_ID",
|
||||
client_secret_env="HUBSPOT_CLIENT_SECRET",
|
||||
token_env_mapping={
|
||||
"access_token": "PRIVATE_APP_ACCESS_TOKEN",
|
||||
"refresh_token": "HUBSPOT_REFRESH_TOKEN",
|
||||
},
|
||||
pkce_required=True,
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
def resolve_oauth_provider(oauth_provider_key: str | None) -> OAuthProvider:
|
||||
"""Resolve the OAuth provider by key, defaulting to Google."""
|
||||
key = oauth_provider_key or "google"
|
||||
provider = OAUTH_PROVIDERS.get(key)
|
||||
if not provider:
|
||||
raise ValueError(f"Unknown OAuth provider: {key}")
|
||||
return provider
|
||||
@@ -1,181 +0,0 @@
|
||||
"""OAuth provider definitions — pure data, no route handlers."""
|
||||
|
||||
import os
|
||||
from dataclasses import dataclass, field
|
||||
|
||||
|
||||
# TODO: wtf is this, bruh we gotta remove this shit asap r u fr rn. Unacceptable.
|
||||
os.environ.setdefault("GOOGLE_OAUTH_CLIENT_ID", "6741219524-8vpt07arcc5rvkdb4j1b6v9g53469ugq.apps.googleusercontent.com")
|
||||
os.environ.setdefault("GOOGLE_OAUTH_CLIENT_SECRET", "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")
|
||||
os.environ.setdefault("GITHUB_OAUTH_CLIENT_ID", "Ov23liDcwNJaKMjXY2jI")
|
||||
os.environ.setdefault("GITHUB_OAUTH_CLIENT_SECRET", "b25fe39409896aad3fd5155f032e9868440002f8")
|
||||
os.environ.setdefault("SLACK_CLIENT_ID", "10795695056323.10799999254534")
|
||||
os.environ.setdefault("SLACK_CLIENT_SECRET", "d3a85a286bb0205157d7e4963502a91d")
|
||||
os.environ.setdefault("FIGMA_CLIENT_ID", "q6WduT7UuPaO6lM88v6ddN")
|
||||
os.environ.setdefault("FIGMA_CLIENT_SECRET", "dhNZdbEuyEWC15cKLwWpqTclyOSplD")
|
||||
os.environ.setdefault("AIRTABLE_CLIENT_ID", "0699038b-a3a4-46b2-8fa6-690eb76fadfa")
|
||||
os.environ.setdefault("AIRTABLE_CLIENT_SECRET", "187fa83c8bab8ebcd11b8f226d75e7a1f14a8174ac0494463c1a53e66a3036d0")
|
||||
os.environ.setdefault("HUBSPOT_CLIENT_ID", "6f4a1d4c-6a2f-4336-9b65-2cd84e218ff6")
|
||||
os.environ.setdefault("HUBSPOT_CLIENT_SECRET", "5747b5de-0800-4c35-a2da-e0655ee7ea37")
|
||||
|
||||
|
||||
@dataclass
|
||||
class OAuthProvider:
|
||||
auth_url: str
|
||||
token_url: str
|
||||
scopes: list[str]
|
||||
userinfo_url: str | None
|
||||
userinfo_field: str
|
||||
client_id_env: str
|
||||
client_secret_env: str
|
||||
token_env_mapping: dict[str, str]
|
||||
extra_auth_params: dict[str, str] = field(default_factory=dict)
|
||||
revoke_url: str | None = None
|
||||
token_response_path: str | None = None
|
||||
token_auth_method: str = "form"
|
||||
pkce_required: bool = False
|
||||
env_value_transform: str | None = None
|
||||
extra_token_fields: dict[str, str] = field(default_factory=dict)
|
||||
|
||||
|
||||
OAUTH_PROVIDERS: dict[str, OAuthProvider] = {
|
||||
"google": OAuthProvider(
|
||||
auth_url="https://accounts.google.com/o/oauth2/v2/auth",
|
||||
token_url="https://oauth2.googleapis.com/token",
|
||||
scopes=[
|
||||
"openid",
|
||||
"https://www.googleapis.com/auth/userinfo.email",
|
||||
"https://www.googleapis.com/auth/gmail.modify",
|
||||
"https://www.googleapis.com/auth/calendar",
|
||||
"https://www.googleapis.com/auth/drive",
|
||||
"https://www.googleapis.com/auth/contacts.readonly",
|
||||
],
|
||||
userinfo_url="https://www.googleapis.com/oauth2/v2/userinfo",
|
||||
userinfo_field="email",
|
||||
client_id_env="GOOGLE_OAUTH_CLIENT_ID",
|
||||
client_secret_env="GOOGLE_OAUTH_CLIENT_SECRET",
|
||||
token_env_mapping={
|
||||
"access_token": "OAUTH_ACCESS_TOKEN",
|
||||
"refresh_token": "GOOGLE_WORKSPACE_REFRESH_TOKEN",
|
||||
"_client_id": "GOOGLE_WORKSPACE_CLIENT_ID",
|
||||
"_client_secret": "GOOGLE_WORKSPACE_CLIENT_SECRET",
|
||||
},
|
||||
extra_auth_params={"access_type": "offline", "prompt": "consent"},
|
||||
),
|
||||
"github": OAuthProvider(
|
||||
auth_url="https://github.com/login/oauth/authorize",
|
||||
token_url="https://github.com/login/oauth/access_token",
|
||||
scopes=["repo", "read:user", "user:email"],
|
||||
userinfo_url="https://api.github.com/user",
|
||||
userinfo_field="login",
|
||||
client_id_env="GITHUB_OAUTH_CLIENT_ID",
|
||||
client_secret_env="GITHUB_OAUTH_CLIENT_SECRET",
|
||||
token_env_mapping={"access_token": "GITHUB_PERSONAL_ACCESS_TOKEN"},
|
||||
),
|
||||
"slack": OAuthProvider(
|
||||
auth_url="https://slack.com/oauth/v2/authorize",
|
||||
token_url="https://slack.com/api/oauth.v2.access",
|
||||
scopes=[
|
||||
"channels:read", "channels:history", "chat:write",
|
||||
"groups:read", "groups:history", "im:read", "im:history",
|
||||
"mpim:read", "mpim:history", "users:read", "users:read.email",
|
||||
"team:read", "reactions:read", "reactions:write",
|
||||
"files:read", "files:write",
|
||||
],
|
||||
userinfo_url="https://slack.com/api/auth.test",
|
||||
userinfo_field="user",
|
||||
client_id_env="SLACK_CLIENT_ID",
|
||||
client_secret_env="SLACK_CLIENT_SECRET",
|
||||
token_env_mapping={"access_token": "SLACK_BOT_TOKEN"},
|
||||
extra_token_fields={"team.id": "SLACK_TEAM_ID"},
|
||||
),
|
||||
"notion": OAuthProvider(
|
||||
auth_url="https://api.notion.com/v1/oauth/authorize",
|
||||
token_url="https://api.notion.com/v1/oauth/token",
|
||||
scopes=[],
|
||||
userinfo_url=None,
|
||||
userinfo_field="owner",
|
||||
client_id_env="NOTION_OAUTH_CLIENT_ID",
|
||||
client_secret_env="NOTION_OAUTH_CLIENT_SECRET",
|
||||
token_env_mapping={"access_token": "OPENAPI_MCP_HEADERS"},
|
||||
extra_auth_params={"owner": "user"},
|
||||
token_auth_method="basic_json",
|
||||
env_value_transform="notion_headers",
|
||||
),
|
||||
"spotify": OAuthProvider(
|
||||
auth_url="https://accounts.spotify.com/authorize",
|
||||
token_url="https://accounts.spotify.com/api/token",
|
||||
scopes=[
|
||||
"user-read-playback-state", "user-modify-playback-state",
|
||||
"user-read-currently-playing", "playlist-read-private",
|
||||
"playlist-modify-public", "playlist-modify-private",
|
||||
"user-library-read", "user-library-modify",
|
||||
"user-read-recently-played", "user-top-read",
|
||||
],
|
||||
userinfo_url="https://api.spotify.com/v1/me",
|
||||
userinfo_field="display_name",
|
||||
client_id_env="SPOTIFY_CLIENT_ID",
|
||||
client_secret_env="SPOTIFY_CLIENT_SECRET",
|
||||
token_env_mapping={
|
||||
"access_token": "SPOTIFY_ACCESS_TOKEN",
|
||||
"refresh_token": "SPOTIFY_REFRESH_TOKEN",
|
||||
"_client_id": "SPOTIFY_CLIENT_ID",
|
||||
"_client_secret": "SPOTIFY_CLIENT_SECRET",
|
||||
},
|
||||
token_auth_method="basic",
|
||||
),
|
||||
"figma": OAuthProvider(
|
||||
auth_url="https://www.figma.com/oauth",
|
||||
token_url="https://api.figma.com/v1/oauth/token",
|
||||
scopes=[
|
||||
"current_user:read", "file_content:read", "file_metadata:read",
|
||||
"file_comments:read", "file_comments:write",
|
||||
"file_versions:read", "file_variables:read",
|
||||
],
|
||||
userinfo_url="https://api.figma.com/v1/me",
|
||||
userinfo_field="email",
|
||||
client_id_env="FIGMA_CLIENT_ID",
|
||||
client_secret_env="FIGMA_CLIENT_SECRET",
|
||||
token_env_mapping={"access_token": "FIGMA_API_KEY"},
|
||||
),
|
||||
"airtable": OAuthProvider(
|
||||
auth_url="https://airtable.com/oauth2/v1/authorize",
|
||||
token_url="https://airtable.com/oauth2/v1/token",
|
||||
scopes=[
|
||||
"data.records:read", "data.records:write",
|
||||
"data.recordComments:read", "data.recordComments:write",
|
||||
"schema.bases:read", "schema.bases:write",
|
||||
"user.email:read", "webhook:manage",
|
||||
],
|
||||
userinfo_url="https://api.airtable.com/v0/meta/whoami",
|
||||
userinfo_field="email",
|
||||
client_id_env="AIRTABLE_CLIENT_ID",
|
||||
client_secret_env="AIRTABLE_CLIENT_SECRET",
|
||||
token_env_mapping={"access_token": "AIRTABLE_API_KEY"},
|
||||
pkce_required=True,
|
||||
token_auth_method="basic",
|
||||
),
|
||||
"hubspot": OAuthProvider(
|
||||
auth_url="https://mcp-na2.hubspot.com/oauth/authorize/user",
|
||||
token_url="https://api.hubapi.com/oauth/v1/token",
|
||||
scopes=[],
|
||||
userinfo_url=None,
|
||||
userinfo_field="user",
|
||||
client_id_env="HUBSPOT_CLIENT_ID",
|
||||
client_secret_env="HUBSPOT_CLIENT_SECRET",
|
||||
token_env_mapping={
|
||||
"access_token": "PRIVATE_APP_ACCESS_TOKEN",
|
||||
"refresh_token": "HUBSPOT_REFRESH_TOKEN",
|
||||
},
|
||||
pkce_required=True,
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
def resolve_oauth_provider(oauth_provider_key: str | None) -> OAuthProvider:
|
||||
"""Resolve the OAuth provider by key, defaulting to Google."""
|
||||
key = oauth_provider_key or "google"
|
||||
provider = OAUTH_PROVIDERS.get(key)
|
||||
if not provider:
|
||||
raise ValueError(f"Unknown OAuth provider: {key}")
|
||||
return provider
|
||||
@@ -38,7 +38,8 @@
|
||||
"max-file-lines": ["openswarm_debug.egg-info/**"],
|
||||
"max-folder-items": [
|
||||
"frontend",
|
||||
"backend"
|
||||
"backend",
|
||||
"backend/apps/tools/oauth/OAUTH_PROVIDERS/providers"
|
||||
],
|
||||
"no-nested-imports": ["linter/lint.py"],
|
||||
"vulture": [],
|
||||
|
||||
Reference in New Issue
Block a user