google-adk-extras 0.2.6__py3-none-any.whl → 0.3.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. google_adk_extras/__init__.py +3 -3
  2. google_adk_extras/adk_builder.py +15 -292
  3. google_adk_extras/artifacts/local_folder_artifact_service.py +0 -2
  4. google_adk_extras/artifacts/mongo_artifact_service.py +0 -1
  5. google_adk_extras/artifacts/s3_artifact_service.py +0 -1
  6. google_adk_extras/artifacts/sql_artifact_service.py +0 -1
  7. google_adk_extras/auth/__init__.py +10 -0
  8. google_adk_extras/auth/attach.py +227 -0
  9. google_adk_extras/auth/config.py +45 -0
  10. google_adk_extras/auth/jwt_utils.py +36 -0
  11. google_adk_extras/auth/sql_store.py +183 -0
  12. google_adk_extras/custom_agent_loader.py +1 -1
  13. google_adk_extras/enhanced_adk_web_server.py +0 -2
  14. google_adk_extras/enhanced_fastapi.py +6 -1
  15. google_adk_extras/memory/mongo_memory_service.py +0 -1
  16. google_adk_extras/memory/sql_memory_service.py +1 -1
  17. google_adk_extras/memory/yaml_file_memory_service.py +1 -3
  18. google_adk_extras/sessions/mongo_session_service.py +0 -1
  19. google_adk_extras/sessions/redis_session_service.py +1 -1
  20. google_adk_extras/sessions/yaml_file_session_service.py +0 -2
  21. google_adk_extras/streaming/streaming_controller.py +2 -2
  22. {google_adk_extras-0.2.6.dist-info → google_adk_extras-0.3.0.dist-info}/METADATA +84 -34
  23. google_adk_extras-0.3.0.dist-info/RECORD +37 -0
  24. google_adk_extras/credentials/__init__.py +0 -34
  25. google_adk_extras/credentials/github_oauth2_credential_service.py +0 -213
  26. google_adk_extras/credentials/google_oauth2_credential_service.py +0 -216
  27. google_adk_extras/credentials/http_basic_auth_credential_service.py +0 -388
  28. google_adk_extras/credentials/jwt_credential_service.py +0 -345
  29. google_adk_extras/credentials/microsoft_oauth2_credential_service.py +0 -250
  30. google_adk_extras/credentials/x_oauth2_credential_service.py +0 -240
  31. google_adk_extras-0.2.6.dist-info/RECORD +0 -39
  32. {google_adk_extras-0.2.6.dist-info → google_adk_extras-0.3.0.dist-info}/WHEEL +0 -0
  33. {google_adk_extras-0.2.6.dist-info → google_adk_extras-0.3.0.dist-info}/licenses/LICENSE +0 -0
  34. {google_adk_extras-0.2.6.dist-info → google_adk_extras-0.3.0.dist-info}/top_level.txt +0 -0
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: google-adk-extras
3
- Version: 0.2.6
4
- Summary: Production-ready services, credentials, and FastAPI wiring for Google ADK
3
+ Version: 0.3.0
4
+ Summary: Production-ready services and FastAPI wiring for Google ADK
5
5
  Home-page: https://github.com/DeadMeme5441/google-adk-extras
6
6
  Author: DeadMeme5441
7
7
  Author-email: DeadMeme5441 <deadunderscorememe@gmail.com>
@@ -49,7 +49,7 @@ Dynamic: requires-python
49
49
  [![Docs](https://img.shields.io/badge/docs-site-brightgreen)](https://deadmeme5441.github.io/google-adk-extras/)
50
50
  [![Docs Build](https://github.com/DeadMeme5441/google-adk-extras/actions/workflows/docs.yml/badge.svg)](https://github.com/DeadMeme5441/google-adk-extras/actions/workflows/docs.yml)
51
51
 
52
- Production-ready extensions for Google ADK (Agent Development Kit). This library adds durable service backends (sessions, artifacts, memory), practical credential services (OAuth2/JWT/Basic), and clean FastAPI wiring so you can run ADK agents with real storage and auth.
52
+ Production-ready extensions for Google ADK (Agent Development Kit). This library adds durable service backends (sessions, artifacts, memory) and clean FastAPI wiring (with optional streaming) so you can run ADK agents with real storage.
53
53
 
54
54
  What this is not: a fork of ADK. It builds on ADK’s core runtime, agents, tools and callbacks, and drops in where ADK expects services and a web server.
55
55
 
@@ -58,10 +58,9 @@ What this is not: a fork of ADK. It builds on ADK’s core runtime, agents, tool
58
58
 
59
59
  ADK provides the core primitives (Runner, Session/State, MemoryService, ArtifactService, CredentialService, Agents/Tools, callbacks, Dev UI, and deployment paths). See the official ADK docs for concepts and APIs.
60
60
 
61
- This package focuses on three gaps common in real apps:
61
+ This package focuses on a few gaps common in real apps:
62
62
  - Durable storage backends beyond in‑memory defaults
63
- - Usable credential flows (Google/GitHub/Microsoft/X OAuth2, JWT, Basic)
64
- - FastAPI integration that accepts your credential service without hacks
63
+ - FastAPI integration with optional streaming (SSE/WS)
65
64
 
66
65
 
67
66
  ## Features
@@ -69,8 +68,7 @@ This package focuses on three gaps common in real apps:
69
68
  - Session services: SQL (SQLite/Postgres/MySQL), MongoDB, Redis, YAML files
70
69
  - Artifact services: Local folder (versioned), S3‑compatible, SQL, MongoDB
71
70
  - Memory services: SQL, MongoDB, Redis, YAML files (term search over text parts)
72
- - Credential services: Google/GitHub/Microsoft/X (OAuth2), JWT, HTTP Basic
73
- - Enhanced FastAPI wiring that respects a provided credential service
71
+ - Enhanced FastAPI wiring for ADK apps (with optional streaming)
74
72
  - Fluent builder (`AdkBuilder`) to assemble a FastAPI app or a Runner
75
73
  - A2A helpers for exposing/consuming agents (see below)
76
74
 
@@ -95,17 +93,18 @@ If you plan to use specific backends, also install their clients (examples):
95
93
  - MongoDB: `uv pip install pymongo`
96
94
  - Redis: `uv pip install redis`
97
95
  - S3: `uv pip install boto3`
98
- - JWT: `uv pip install PyJWT`
96
+
97
+ Note on credentials (0.3.0): Outbound credentials for tools remain ADK’s concern (use ADK’s BaseCredentialService). Inbound API authentication is now available as an optional FastAPI layer in this package (see Auth below). You can run fully open (no auth) or enable API Key, Basic, or JWT (including first‑party issuance backed by SQL).
99
98
 
100
99
 
101
100
  ## Quickstart (FastAPI)
102
101
 
103
- Use the fluent builder to wire services and credentials. Then run with uvicorn.
102
+ Use the fluent builder to wire services. Then run with uvicorn.
104
103
 
105
104
  ```python
106
105
  # app.py
107
106
  from google_adk_extras import AdkBuilder
108
- from google_adk_extras.credentials import GoogleOAuth2CredentialService
107
+ from google_adk_extras.auth import AuthConfig, JwtIssuerConfig, JwtValidatorConfig
109
108
 
110
109
  app = (
111
110
  AdkBuilder()
@@ -113,11 +112,7 @@ app = (
113
112
  .with_session_service("sqlite:///./sessions.db") # or: mongodb://, redis://, yaml://
114
113
  .with_artifact_service("local://./artifacts") # or: s3://bucket, mongodb://, sql://
115
114
  .with_memory_service("yaml://./memory") # or: redis://, mongodb://, sql://
116
- .with_credential_service(GoogleOAuth2CredentialService(
117
- client_id="…apps.googleusercontent.com",
118
- client_secret="…",
119
- scopes=["openid", "email", "profile"],
120
- ))
115
+ # credentials: rely on ADK defaults or pass an ADK BaseCredentialService if needed
121
116
  .with_web_ui(True) # serve ADK’s dev UI if assets available
122
117
  .with_agent_reload(True)
123
118
  .build_fastapi_app()
@@ -133,6 +128,77 @@ uvicorn app:app --reload
133
128
  If you don’t keep agents on disk, register them programmatically and use a custom loader (see below).
134
129
 
135
130
 
131
+ ## Auth (optional)
132
+
133
+ Auth is entirely optional. By default, all endpoints are open (no auth). To enable protection, pass `auth_config` into `get_enhanced_fast_api_app` via the builder or directly.
134
+
135
+ Supported inbound methods:
136
+ - API Key: `X-API-Key: <key>` header (or `?api_key=` query). Keys can be static via config, or issued/rotated via SQL‑backed endpoints.
137
+ - HTTP Basic: `Authorization: Basic base64(user:pass)` for quick human/internal testing. Can validate against in‑memory map or the SQL users table.
138
+ - Bearer JWT (validate): Accept JWTs from Google/Auth0/Okta/etc. via JWKS, or HS256 secret in dev. Enforces iss/aud/exp/nbf.
139
+ - Bearer JWT (issue): First‑party issuer with HS256, tokens minted from `/auth/token`, users stored in SQL (SQLite/Postgres/MySQL).
140
+
141
+ Minimal enablement (JWT validate only):
142
+
143
+ ```python
144
+ from google_adk_extras.auth import AuthConfig, JwtValidatorConfig
145
+
146
+ auth = AuthConfig(
147
+ enabled=True,
148
+ jwt_validator=JwtValidatorConfig(
149
+ jwks_url="https://accounts.google.com/.well-known/openid-configuration", # example
150
+ issuer="https://accounts.google.com",
151
+ audience="your-api-audience",
152
+ ),
153
+ )
154
+
155
+ app = (
156
+ AdkBuilder()
157
+ .with_agents_dir("./agents")
158
+ .build_fastapi_app()
159
+ )
160
+ ```
161
+
162
+ First‑party issuer + validate (single shared HS256 secret) with SQL connector:
163
+
164
+ ```python
165
+ from google_adk_extras.auth import AuthConfig, JwtIssuerConfig, JwtValidatorConfig
166
+
167
+ issuer = JwtIssuerConfig(
168
+ enabled=True,
169
+ issuer="https://local-issuer",
170
+ audience="adk-api",
171
+ algorithm="HS256",
172
+ hs256_secret="topsecret",
173
+ database_url="sqlite:///./auth.db", # also supports Postgres/MySQL
174
+ )
175
+ validator = JwtValidatorConfig(
176
+ issuer=issuer.issuer,
177
+ audience=issuer.audience,
178
+ hs256_secret=issuer.hs256_secret,
179
+ )
180
+
181
+ auth = AuthConfig(enabled=True, jwt_issuer=issuer, jwt_validator=validator)
182
+
183
+ app = (
184
+ AdkBuilder()
185
+ .with_agents_dir("./agents")
186
+ .build_fastapi_app()
187
+ )
188
+ ```
189
+
190
+ Issuing and using tokens/keys at runtime:
191
+ - Register user: `POST /auth/register?username=alice&password=wonder`
192
+ - Token (password): `POST /auth/token?grant_type=password&username=alice&password=wonder`
193
+ - Refresh: `POST /auth/refresh?user_id=<uid>&refresh_token=<jti>`
194
+ - Create API key: `POST /auth/api-keys` (auth required) → returns `{ id, api_key }` (plaintext shown once)
195
+ - List keys: `GET /auth/api-keys` (auth required)
196
+ - Revoke key: `DELETE /auth/api-keys/{id}` (auth required)
197
+ - Use API key: add `X-API-Key: <api_key>` to any protected route (keys currently allow full access)
198
+
199
+ Protected routes include `/run`, `/run_sse`, all `/apps/...` session/artifact/eval endpoints, `/debug/*`, `/builder/*`, and optionally `/list-apps` and `/apps/{app}/metrics-info`.
200
+
201
+
136
202
  ## Quickstart (Runner)
137
203
 
138
204
  Create a Runner wired with your chosen backends. Use agent name (filesystem loader) or pass an agent instance.
@@ -251,24 +317,8 @@ app = (
251
317
  ```
252
318
 
253
319
 
254
- ## Credential URI cheatsheet (optional)
255
-
256
- If you prefer URIs instead of constructing services:
257
-
258
- - Google OAuth2: `oauth2-google://client_id:secret@scopes=openid,email,profile`
259
- - GitHub OAuth2: `oauth2-github://client_id:secret@scopes=user,repo`
260
- - Microsoft OAuth2: `oauth2-microsoft://<tenant>/<client_id>:<secret>@scopes=User.Read`
261
- - X OAuth2: `oauth2-x://client_id:secret@scopes=tweet.read,users.read`
262
- - JWT: `jwt://<secret>@algorithm=HS256&issuer=my-app&audience=api.example.com&expiration_minutes=60`
263
- - Basic: `basic-auth://username:password@realm=My%20API`
264
-
265
- ```python
266
- cred = (
267
- AdkBuilder()
268
- .with_credential_service_uri("jwt://secret@issuer=my-app")
269
- ._create_credential_service()
270
- )
271
- ```
320
+ <!-- Credential URI helpers removed. Use ADK’s BaseCredentialService directly if needed,
321
+ and handle inbound API authentication at FastAPI level. -->
272
322
 
273
323
 
274
324
  ## Notes & limitations
@@ -0,0 +1,37 @@
1
+ google_adk_extras/__init__.py,sha256=deMaothLZ-UWkfMdfIV186oMu9ueatO1pT8mpBrJnw8,851
2
+ google_adk_extras/adk_builder.py,sha256=Ax5e_NegGZcdb_xm4t4e18gpJjcR5ICn0Zefy6VuLh4,30068
3
+ google_adk_extras/custom_agent_loader.py,sha256=e_sgA58RmDzCUHCySAi3Hruxumtozw3UScZV2vxlCbw,5991
4
+ google_adk_extras/enhanced_adk_web_server.py,sha256=4QxTADlQv6oXaAEVMQc7-bpf84jCrTkN6pJC6R2jmww,5348
5
+ google_adk_extras/enhanced_fastapi.py,sha256=xoWh9wibhxc48fEpLyQrkb2gB8Cas75_fwZzKWoRMic,28454
6
+ google_adk_extras/enhanced_runner.py,sha256=b7O1a9-4S49LduILOEDs6IxjCI4w_E39sc-Hs4y3Rys,1410
7
+ google_adk_extras/artifacts/__init__.py,sha256=_IsKDgf6wanWR0HXvSpK9SiLa3n5URKLtazkKyH1P-o,931
8
+ google_adk_extras/artifacts/base_custom_artifact_service.py,sha256=O9rkc250B3yDRYbyDI0EvTrCKvnih5_DQas5OF-hRMY,9721
9
+ google_adk_extras/artifacts/local_folder_artifact_service.py,sha256=7oepQIHYimXxSjGl3-i1HgZ595H9hZWa3OptsMeyqgU,12509
10
+ google_adk_extras/artifacts/mongo_artifact_service.py,sha256=K46Ycl7gkzCbCweVL0GrWsFxCcJ3T7JnE9gpIamfd6Y,7099
11
+ google_adk_extras/artifacts/s3_artifact_service.py,sha256=inIc2KL3OdIQGkCA_HYJE0ZfGFQ3YcX_SFZEFVUb0T8,15655
12
+ google_adk_extras/artifacts/sql_artifact_service.py,sha256=OovKSzM0nib2c-pzkv7NYyiHi8kFK-k3SFOMi92U4Mk,11980
13
+ google_adk_extras/auth/__init__.py,sha256=PQQmFAjOPrt9tAGHOtQC-_U7fpRd8Dt_vh973b2pSnc,202
14
+ google_adk_extras/auth/attach.py,sha256=eEnT7vvsb0ZQUKQI8ijgIziTrRTiyc1aPV0LwXBWtmU,10020
15
+ google_adk_extras/auth/config.py,sha256=JGJefyExVG3QFjmAkgTT-yaMivCvkOs4E7HwMlqVES0,1573
16
+ google_adk_extras/auth/jwt_utils.py,sha256=sWIQWa1lGrottv6kzxo6cgTZFBa7J7wSa2-aJIVxfM8,1290
17
+ google_adk_extras/auth/sql_store.py,sha256=-LouLrcT4gBBGrwG4kqbMyjVo1W1BbugPCKZUUFklWs,6693
18
+ google_adk_extras/credentials/base_custom_credential_service.py,sha256=iYHacJAsZmDfpxLOPYx4tQpbtWTbwC75tRp6hlZFoSg,4014
19
+ google_adk_extras/memory/__init__.py,sha256=2FFJXw9CZHctKXmCuc-lrdETeQ5xqdivy3oarHJz5gs,994
20
+ google_adk_extras/memory/base_custom_memory_service.py,sha256=TRQMaXiRg2LXFwYZnFHoL-yBVtecuX1ownyPBJf6Xww,3613
21
+ google_adk_extras/memory/mongo_memory_service.py,sha256=toXp7lg0el247zxY8HURY_7VxoaAPViZKnbvLCUxdWU,6747
22
+ google_adk_extras/memory/redis_memory_service.py,sha256=P6vYvP8gv6kCH1lRB0SQld3mzS_JVKMUDtKifXDfu38,7400
23
+ google_adk_extras/memory/sql_memory_service.py,sha256=cvAOsBZCFN3ruj0weuwvihgAnnvRJMO6HYMZX58rG9k,10760
24
+ google_adk_extras/memory/yaml_file_memory_service.py,sha256=yx-nPqxXWxg9RI4OiwMAbdXs-eX1nBb1LzSWvib28S0,9909
25
+ google_adk_extras/sessions/__init__.py,sha256=VgHyPULLzjJD7ShsyABz98rWVND0mOoM6qX74MrTJwA,915
26
+ google_adk_extras/sessions/base_custom_session_service.py,sha256=npwrSNAtgqN6K7C8e4idiWkFNr_3pcOAiFYpGXu3NnI,8912
27
+ google_adk_extras/sessions/mongo_session_service.py,sha256=Wo_dnsbnEex5rWeGOj5RABRhMICeaa4x--QBJPSur-4,8317
28
+ google_adk_extras/sessions/redis_session_service.py,sha256=0G4yHWCngZz5w3UnQEigHXhgAqwttE8BTTYiDA1Hl7c,10428
29
+ google_adk_extras/sessions/sql_session_service.py,sha256=TaOeEVWnwQ_8nvDZBW7e3qhzR_ecuGsjvZ_kh6Guq8g,14558
30
+ google_adk_extras/sessions/yaml_file_session_service.py,sha256=g65ptJWAMVN4XQmCxQ0UwnSC2GU1NJ6QRvrwfzSK_xo,11797
31
+ google_adk_extras/streaming/__init__.py,sha256=rcjmlCJHTlvUiCrx6qNGw5ObCnEtfENkGTvzfEiGL0M,461
32
+ google_adk_extras/streaming/streaming_controller.py,sha256=Z72k5QgvWBIU2YP8iXlc3D3oWxDYWJo9eygj_KzALYA,10489
33
+ google_adk_extras-0.3.0.dist-info/licenses/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
34
+ google_adk_extras-0.3.0.dist-info/METADATA,sha256=EX-DwXDezDXZVSLkGwTb36T-4pS_DWQgXRmCPDx5Gcw,12867
35
+ google_adk_extras-0.3.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
36
+ google_adk_extras-0.3.0.dist-info/top_level.txt,sha256=DDWgVkz8G8ihPzznxAWyKa2jgJW3F6Fwy__qMddoKTs,18
37
+ google_adk_extras-0.3.0.dist-info/RECORD,,
@@ -1,34 +0,0 @@
1
- """Custom credential service implementations for Google ADK.
2
-
3
- Optional services are imported lazily to avoid import-time failures when
4
- their third-party dependencies are not installed.
5
- """
6
-
7
- from .base_custom_credential_service import BaseCustomCredentialService
8
- from .google_oauth2_credential_service import GoogleOAuth2CredentialService
9
- from .github_oauth2_credential_service import GitHubOAuth2CredentialService
10
- from .microsoft_oauth2_credential_service import MicrosoftOAuth2CredentialService
11
- from .x_oauth2_credential_service import XOAuth2CredentialService
12
- from .http_basic_auth_credential_service import (
13
- HTTPBasicAuthCredentialService,
14
- HTTPBasicAuthWithCredentialsService,
15
- )
16
-
17
- # Optional: JWT (requires PyJWT)
18
- try:
19
- from .jwt_credential_service import JWTCredentialService # type: ignore
20
- except Exception: # ImportError or transitive import errors
21
- JWTCredentialService = None # type: ignore
22
-
23
- __all__ = [
24
- "BaseCustomCredentialService",
25
- "GoogleOAuth2CredentialService",
26
- "GitHubOAuth2CredentialService",
27
- "MicrosoftOAuth2CredentialService",
28
- "XOAuth2CredentialService",
29
- "HTTPBasicAuthCredentialService",
30
- "HTTPBasicAuthWithCredentialsService",
31
- ]
32
-
33
- if JWTCredentialService is not None:
34
- __all__.append("JWTCredentialService")
@@ -1,213 +0,0 @@
1
- """GitHub OAuth2 credential service implementation."""
2
-
3
- from typing import Optional, List
4
- import logging
5
-
6
- from google.adk.auth.credential_service.session_state_credential_service import SessionStateCredentialService
7
- from google.adk.auth.credential_service.base_credential_service import CallbackContext
8
- from google.adk.auth import AuthConfig, AuthCredential, AuthCredentialTypes
9
- from google.adk.auth.auth_credential import OAuth2Auth
10
- from fastapi.openapi.models import OAuth2
11
- from fastapi.openapi.models import OAuthFlowAuthorizationCode, OAuthFlows
12
-
13
- from .base_custom_credential_service import BaseCustomCredentialService
14
-
15
- logger = logging.getLogger(__name__)
16
-
17
-
18
- class GitHubOAuth2CredentialService(BaseCustomCredentialService):
19
- """GitHub OAuth2 credential service for handling GitHub authentication flows.
20
-
21
- This service provides pre-configured OAuth2 flows for GitHub APIs including
22
- repository access, user information, and organization management.
23
-
24
- Args:
25
- client_id: The GitHub OAuth2 client ID from GitHub Developer Settings.
26
- client_secret: The GitHub OAuth2 client secret from GitHub Developer Settings.
27
- scopes: List of OAuth2 scopes to request. Common scopes include:
28
- - "user" - Access to user profile information
29
- - "user:email" - Access to user email addresses
30
- - "repo" - Full access to repositories
31
- - "public_repo" - Access to public repositories only
32
- - "admin:org" - Full access to organization data
33
- - "read:org" - Read access to organization data
34
- - "notifications" - Access to notifications
35
- use_session_state: If True, stores credentials in session state. If False,
36
- uses in-memory storage. Default is True for persistence.
37
-
38
- Example:
39
- ```python
40
- credential_service = GitHubOAuth2CredentialService(
41
- client_id="your-github-client-id",
42
- client_secret="your-github-client-secret",
43
- scopes=["user", "repo", "read:org"]
44
- )
45
- await credential_service.initialize()
46
-
47
- # Use with Runner
48
- runner = Runner(
49
- agent=agent,
50
- session_service=session_service,
51
- credential_service=credential_service,
52
- app_name="my_app"
53
- )
54
- ```
55
- """
56
-
57
- # GitHub OAuth2 endpoints
58
- GITHUB_AUTH_URL = "https://github.com/login/oauth/authorize"
59
- GITHUB_TOKEN_URL = "https://github.com/login/oauth/access_token"
60
-
61
- # Common GitHub OAuth2 scopes
62
- COMMON_SCOPES = {
63
- "user": "Access to user profile information",
64
- "user:email": "Access to user email addresses",
65
- "user:follow": "Access to follow/unfollow users",
66
- "repo": "Full access to public and private repositories",
67
- "public_repo": "Access to public repositories only",
68
- "repo:status": "Access to commit status",
69
- "repo_deployment": "Access to deployment status",
70
- "admin:org": "Full control of orgs and teams, read/write org projects",
71
- "write:org": "Read and write access to organization membership and projects",
72
- "read:org": "Read-only access to organization membership and projects",
73
- "admin:public_key": "Full control of user public keys",
74
- "write:public_key": "Write access to user public keys",
75
- "read:public_key": "Read access to user public keys",
76
- "admin:repo_hook": "Full control of repository hooks",
77
- "write:repo_hook": "Write access to repository hooks",
78
- "read:repo_hook": "Read access to repository hooks",
79
- "admin:org_hook": "Full control of organization hooks",
80
- "gist": "Write access to gists",
81
- "notifications": "Access to notifications",
82
- "delete_repo": "Delete repositories",
83
- "write:packages": "Upload packages to GitHub Package Registry",
84
- "read:packages": "Download packages from GitHub Package Registry",
85
- "workflow": "Update GitHub Action workflows"
86
- }
87
-
88
- def __init__(
89
- self,
90
- client_id: str,
91
- client_secret: str,
92
- scopes: Optional[List[str]] = None,
93
- use_session_state: bool = True
94
- ):
95
- """Initialize the GitHub OAuth2 credential service.
96
-
97
- Args:
98
- client_id: GitHub OAuth2 client ID.
99
- client_secret: GitHub OAuth2 client secret.
100
- scopes: List of OAuth2 scopes to request.
101
- use_session_state: Whether to use session state for credential storage.
102
- """
103
- super().__init__()
104
- self.client_id = client_id
105
- self.client_secret = client_secret
106
- self.scopes = scopes or ["user", "repo"]
107
- self.use_session_state = use_session_state
108
-
109
- # Underlying credential service for storage
110
- if use_session_state:
111
- self._storage_service = SessionStateCredentialService()
112
- else:
113
- from google.adk.auth.credential_service.in_memory_credential_service import InMemoryCredentialService
114
- self._storage_service = InMemoryCredentialService()
115
-
116
- async def _initialize_impl(self) -> None:
117
- """Initialize the GitHub OAuth2 credential service.
118
-
119
- Validates the client credentials and sets up the OAuth2 auth scheme.
120
-
121
- Raises:
122
- ValueError: If client_id or client_secret is missing.
123
- """
124
- if not self.client_id:
125
- raise ValueError("GitHub OAuth2 client_id is required")
126
- if not self.client_secret:
127
- raise ValueError("GitHub OAuth2 client_secret is required")
128
- if not self.scopes:
129
- raise ValueError("At least one OAuth2 scope is required")
130
-
131
- # Validate scopes against known GitHub scopes
132
- unknown_scopes = set(self.scopes) - set(self.COMMON_SCOPES.keys())
133
- if unknown_scopes:
134
- logger.warning(f"Unknown GitHub OAuth2 scopes: {unknown_scopes}")
135
-
136
- logger.info(f"Initialized GitHub OAuth2 credential service with scopes: {self.scopes}")
137
-
138
- def create_auth_config(self) -> AuthConfig:
139
- """Create an AuthConfig for GitHub OAuth2 authentication.
140
-
141
- Returns:
142
- AuthConfig: Configured auth config for GitHub OAuth2 flow.
143
- """
144
- self._check_initialized()
145
-
146
- # Create OAuth2 auth scheme
147
- auth_scheme = OAuth2(
148
- flows=OAuthFlows(
149
- authorizationCode=OAuthFlowAuthorizationCode(
150
- authorizationUrl=self.GITHUB_AUTH_URL,
151
- tokenUrl=self.GITHUB_TOKEN_URL,
152
- scopes={
153
- scope: self.COMMON_SCOPES.get(scope, f"GitHub scope: {scope}")
154
- for scope in self.scopes
155
- }
156
- )
157
- )
158
- )
159
-
160
- # Create OAuth2 credential
161
- auth_credential = AuthCredential(
162
- auth_type=AuthCredentialTypes.OAUTH2,
163
- oauth2=OAuth2Auth(
164
- client_id=self.client_id,
165
- client_secret=self.client_secret
166
- )
167
- )
168
-
169
- return AuthConfig(
170
- auth_scheme=auth_scheme,
171
- raw_auth_credential=auth_credential
172
- )
173
-
174
- async def load_credential(
175
- self,
176
- auth_config: AuthConfig,
177
- callback_context: CallbackContext,
178
- ) -> Optional[AuthCredential]:
179
- """Load GitHub OAuth2 credential from storage.
180
-
181
- Args:
182
- auth_config: The auth config containing credential key information.
183
- callback_context: The current callback context.
184
-
185
- Returns:
186
- Optional[AuthCredential]: The stored credential or None if not found.
187
- """
188
- self._check_initialized()
189
- return await self._storage_service.load_credential(auth_config, callback_context)
190
-
191
- async def save_credential(
192
- self,
193
- auth_config: AuthConfig,
194
- callback_context: CallbackContext,
195
- ) -> None:
196
- """Save GitHub OAuth2 credential to storage.
197
-
198
- Args:
199
- auth_config: The auth config containing the credential to save.
200
- callback_context: The current callback context.
201
- """
202
- self._check_initialized()
203
- await self._storage_service.save_credential(auth_config, callback_context)
204
-
205
- logger.info(f"Saved GitHub OAuth2 credential for user {callback_context._invocation_context.user_id}")
206
-
207
- def get_supported_scopes(self) -> dict:
208
- """Get dictionary of supported GitHub OAuth2 scopes and their descriptions.
209
-
210
- Returns:
211
- dict: Mapping of scope names to descriptions.
212
- """
213
- return self.COMMON_SCOPES.copy()