-
Notifications
You must be signed in to change notification settings - Fork 81
feat: support short-lived tokens endpoint #517
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
WalkthroughThis pull request introduces authentication management capabilities into the Deepgram SDK. New properties in the Changes
Sequence Diagram(s)Synchronous Token GenerationsequenceDiagram
participant App as Application/Main
participant Client as DeepgramClient
participant AuthSync as AuthRESTClient
participant AuthServer as Authentication Service
App->>Client: Instantiate DeepgramClient (with API key)
Client->>AuthSync: Retrieve auth property (v1 instance)
AuthSync->>AuthServer: POST /grant_token (with API key)
AuthServer-->>AuthSync: Return GrantTokenResponse (JWT and TTL)
AuthSync-->>Client: Return token
Client-->>App: Provide token result
Asynchronous Token GenerationsequenceDiagram
participant App as Async Application/Main
participant Client as DeepgramClient
participant AuthAsync as AsyncAuthRESTClient
participant AuthServer as Authentication Service
App->>Client: Instantiate DeepgramClient (with API key)
Client->>AuthAsync: Retrieve asyncauth property (v1 instance)
AuthAsync->>AuthServer: Async POST /grant_token (with API key)
AuthServer-->>AuthAsync: Return GrantTokenResponse (JWT and TTL)
AuthAsync-->>Client: Return token asynchronously
Client-->>App: Provide token result asynchronously
Tip ⚡💬 Agentic Chat (Pro Plan, General Availability)
📜 Recent review detailsConfiguration used: CodeRabbit UI 📒 Files selected for processing (2)
🚧 Files skipped from review as they are similar to previous changes (2)
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 10
🧹 Nitpick comments (12)
examples/auth/token/main.py (3)
18-20
: Remove unused AUDIO_URL constantThe
AUDIO_URL
constant is defined but never used in the script. Since this example demonstrates the authentication flow rather than audio processing, this constant appears to be unnecessary.-AUDIO_URL = { - "url": "https://static.deepgram.com/examples/Bueller-Life-moves-pretty-fast.wav" -}
10-14
: Remove unused importThe
PrerecordedOptions
import is not used in this example script and should be removed.from deepgram import ( DeepgramClient, - PrerecordedOptions, DeepgramClientOptions )
23-36
: Add docstring to main functionAdding a docstring to the
main
function would improve code documentation and provide clarity about the example's purpose.def main(): + """ + Demonstrates how to generate a short-lived authentication token using the Deepgram SDK. + + This example initializes a Deepgram client and calls the grant_token method + to generate a temporary JWT with a 30-second TTL. + """ try: # STEP 1 Create a Deepgram client using the DEEPGRAM_API_KEY from your environment variables config = DeepgramClientOptions( verbose=verboselogs.SPAM, )deepgram/clients/auth/v1/async_client.py (2)
41-42
: Update log message to use correct class name.The log message incorrectly uses "AuthRestClient" instead of "AsyncAuthRestClient".
- self._logger.debug("AuthRestClient.grant_token ENTER") + self._logger.debug("AsyncAuthRestClient.grant_token ENTER")
50-51
: Update log message to use correct class name.The log message incorrectly uses "AuthRestClient" instead of "AsyncAuthRestClient".
- self._logger.debug("AuthRestClient.grant_token LEAVE") + self._logger.debug("AsyncAuthRestClient.grant_token LEAVE")deepgram/clients/auth/v1/client.py (2)
35-36
: Fix docstring return type descriptionThe docstring incorrectly states the return type contains "transcription result" when it should reference a token or authentication result.
Returns: - GrantTokenResponse: An object containing the transcription result. + GrantTokenResponse: An object containing the authentication token and expiry information.
41-51
: Consider adding error handling for network failuresThe current implementation doesn't have explicit error handling for network failures or API errors. Consider adding try/except blocks to handle potential errors and provide meaningful error messages.
self._logger.debug("AuthRestClient.grant_token ENTER") url = f"{self._config.url}/{self._endpoint}" self._logger.info("url: %s", url) - result = self.post(url, headers={"auth": self._config.api_key}) - self._logger.info("json: %s", result) - res = GrantTokenResponse.from_json(result) + try: + result = self.post(url, headers={"auth": self._config.api_key}) + self._logger.info("json: %s", result) + res = GrantTokenResponse.from_json(result) + except Exception as e: + self._logger.error("Failed to grant token: %s", str(e)) + raise self._logger.verbose("result: %s", res) self._logger.notice("grant_token succeeded") self._logger.debug("AuthRestClient.grant_token LEAVE") return resexamples/auth/async_token/main.py (5)
19-21
: Remove unused AUDIO_URL constantThe AUDIO_URL constant is defined but never used in this example. Since this example demonstrates token generation, not audio transcription, this constant should be removed to avoid confusion.
-AUDIO_URL = { - "url": "https://static.deepgram.com/examples/Bueller-Life-moves-pretty-fast.wav" -}
11-15
: Remove unused importsThe
PrerecordedOptions
is imported but never used in this example. Consider removing unused imports to keep the code clean.from deepgram import ( DeepgramClient, - PrerecordedOptions, DeepgramClientOptions )
33-33
: Add comment explaining version selection syntaxThe
.v("1")
method call isn't immediately intuitive. Consider adding a comment to explain that this selects the API version.# STEP 2 Call the grant_token method on the auth rest class + # Use v("1") to select API version 1 response = await deepgram.asyncauth.v("1").grant_token()
35-36
: Improve error handling with specific exception typesThe current exception handling catches all exceptions with a generic handler. Consider catching specific exception types to provide more helpful error messages.
response = await deepgram.asyncauth.v("1").grant_token() print(f"response: {response}\n\n") - except Exception as e: - print(f"Exception: {e}") + except ConnectionError as e: + print(f"Connection error: {e}") + except ValueError as e: + print(f"Value error: {e}") + except Exception as e: + print(f"Unexpected error: {e}")
24-37
: Add return statement to main functionThe main function could return the response or a status code to indicate success or failure, which would be useful if this example is used as a reference for other applications.
async def main(): try: # STEP 1 Create a Deepgram client using the DEEPGRAM_API_KEY from your environment variables config = DeepgramClientOptions( verbose=verboselogs.SPAM, ) deepgram: DeepgramClient = DeepgramClient(os.environ.get("DEEPGRAM_API_KEY"), config) # STEP 2 Call the grant_token method on the auth rest class response = await deepgram.asyncauth.v("1").grant_token() print(f"response: {response}\n\n") + return 0 # Success except Exception as e: print(f"Exception: {e}") + return 1 # Error
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (10)
deepgram/client.py
(3 hunks)deepgram/clients/__init__.py
(1 hunks)deepgram/clients/auth/__init__.py
(1 hunks)deepgram/clients/auth/client.py
(1 hunks)deepgram/clients/auth/v1/__init__.py
(1 hunks)deepgram/clients/auth/v1/async_client.py
(1 hunks)deepgram/clients/auth/v1/client.py
(1 hunks)deepgram/clients/auth/v1/response.py
(1 hunks)examples/auth/async_token/main.py
(1 hunks)examples/auth/token/main.py
(1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (9)
examples/auth/token/main.py (4)
deepgram/client.py (3)
DeepgramClient
(408-668)auth
(507-511)v
(597-666)deepgram/options.py (1)
DeepgramClientOptions
(17-136)deepgram/clients/auth/v1/async_client.py (1)
grant_token
(31-51)deepgram/clients/auth/v1/client.py (1)
grant_token
(31-51)
deepgram/clients/auth/v1/response.py (1)
deepgram/clients/common/v1/shared_response.py (1)
BaseResponse
(16-44)
deepgram/clients/auth/v1/__init__.py (3)
deepgram/clients/auth/v1/client.py (1)
AuthRESTClient
(13-51)deepgram/clients/auth/v1/async_client.py (1)
AsyncAuthRESTClient
(13-51)deepgram/clients/auth/v1/response.py (1)
GrantTokenResponse
(13-24)
deepgram/clients/auth/v1/async_client.py (3)
deepgram/options.py (1)
DeepgramClientOptions
(17-136)deepgram/clients/common/v1/abstract_async_rest.py (1)
AbstractAsyncRestClient
(16-383)deepgram/clients/auth/v1/response.py (1)
GrantTokenResponse
(13-24)
deepgram/clients/auth/__init__.py (3)
deepgram/clients/auth/v1/client.py (1)
AuthRESTClient
(13-51)deepgram/clients/auth/v1/async_client.py (1)
AsyncAuthRESTClient
(13-51)deepgram/clients/auth/v1/response.py (1)
GrantTokenResponse
(13-24)
deepgram/clients/auth/client.py (3)
deepgram/clients/auth/v1/client.py (1)
AuthRESTClient
(13-51)deepgram/clients/auth/v1/async_client.py (1)
AsyncAuthRESTClient
(13-51)deepgram/clients/auth/v1/response.py (1)
GrantTokenResponse
(13-24)
examples/auth/async_token/main.py (3)
deepgram/client.py (3)
DeepgramClient
(408-668)asyncauth
(514-518)v
(597-666)deepgram/options.py (1)
DeepgramClientOptions
(17-136)deepgram/clients/auth/v1/async_client.py (1)
grant_token
(31-51)
deepgram/clients/auth/v1/client.py (5)
deepgram/options.py (1)
DeepgramClientOptions
(17-136)deepgram/clients/common/v1/abstract_sync_rest.py (1)
AbstractSyncRestClient
(16-375)deepgram/clients/auth/v1/response.py (1)
GrantTokenResponse
(13-24)deepgram/utils/verboselogs/__init__.py (3)
VerboseLogger
(119-168)verbose
(165-168)notice
(150-153)deepgram/clients/auth/v1/async_client.py (1)
grant_token
(31-51)
deepgram/clients/__init__.py (3)
deepgram/clients/auth/v1/client.py (1)
AuthRESTClient
(13-51)deepgram/clients/auth/v1/async_client.py (1)
AsyncAuthRESTClient
(13-51)deepgram/clients/auth/v1/response.py (1)
GrantTokenResponse
(13-24)
🪛 GitHub Actions: Check - static
deepgram/clients/auth/v1/response.py
[error] 17-17: mypy: Incompatible types in assignment (expression has type 'None', variable has type 'str')
🔇 Additional comments (9)
deepgram/clients/auth/v1/response.py (1)
12-24
: Response structure looks goodThe
GrantTokenResponse
class properly inherits fromBaseResponse
and includes appropriate fields for an authentication token response with JSON field name mappings. The default expiration of 30 seconds for short-lived tokens is a common practice.🧰 Tools
🪛 GitHub Actions: Check - static
[error] 17-17: mypy: Incompatible types in assignment (expression has type 'None', variable has type 'str')
examples/auth/token/main.py (1)
1-40
: Good example implementationOverall, this example effectively demonstrates the new short-lived token functionality. It properly initializes the Deepgram client, calls the grant_token method, and handles potential exceptions. The step-by-step comments are helpful for users learning how to use this feature.
deepgram/clients/auth/client.py (1)
5-11
: Versioning pattern implemented correctly.The file sets up a clean versioning facade for the authentication clients, following the SDK's established pattern. This approach allows for future version updates while maintaining backward compatibility.
deepgram/client.py (5)
251-257
: Auth client imports added correctly.The imports for the authentication-related classes are appropriately added, following the import organization pattern used throughout the file.
506-512
: Auth property added correctly.The
auth
property is well-implemented and follows the same pattern as other client properties in the class. The docstring clearly describes its purpose.
513-519
: AsyncAuth property added correctly.The
asyncauth
property is well-implemented and follows the same pattern as other async client properties in the class. The docstring clearly describes its purpose.
631-635
: Auth versioning handler added correctly.The "auth" case is properly added to the version handling logic in the
v
method, making it consistent with how other client types are versioned.
635-639
: AsyncAuth versioning handler added correctly.The "asyncauth" case is properly added to the version handling logic in the
v
method, making it consistent with how other async client types are versioned.deepgram/clients/__init__.py (1)
315-320
: Auth module imports added correctly.The imports for the authentication-related classes and response types are appropriately added, following the organizational pattern used throughout the file.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (2)
deepgram/clients/auth/v1/response.py (2)
21-24
: Clarify the time unit for expires_in.The
expires_in
field has a default value of 30, but the code doesn't specify what time unit this represents (seconds, minutes, hours). Consider enhancing the docstring to clarify this.expires_in: int = field( metadata=dataclass_config(field_name='expires_in'), default=30, + # Default token expiration time in seconds )
Also, consider adding field-level docstrings for better API documentation:
@dataclass class GrantTokenResponse(BaseResponse): """ The response object for the authentication grant token endpoint. + + Attributes: + access_token: The token string used for authentication + expires_in: Number of seconds until the token expires """
12-24
: Consider validation for expires_in field.For authentication tokens, the expiration time should always be a positive value. Consider adding validation to ensure that
expires_in
is greater than zero, either through a post-init check or a property setter.@dataclass class GrantTokenResponse(BaseResponse): """ The response object for the authentication grant token endpoint. """ access_token: str = field( metadata=dataclass_config(field_name='access_token'), default="", ) expires_in: int = field( metadata=dataclass_config(field_name='expires_in'), default=30, ) + + def __post_init__(self): + """Validate that expires_in is a positive integer.""" + if self.expires_in <= 0: + raise ValueError("expires_in must be a positive integer")
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
deepgram/clients/auth/v1/response.py
(1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
deepgram/clients/auth/v1/response.py (1)
deepgram/clients/common/v1/shared_response.py (1)
BaseResponse
(16-44)
🔇 Additional comments (1)
deepgram/clients/auth/v1/response.py (1)
17-20
: Access token default value looks good.Your implementation of the
access_token
field with an empty string default value addresses the previous type mismatch issue correctly. This ensures type consistency while providing a sensible default.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (1)
deepgram/clients/auth/v1/async_client.py (1)
23-30
: Consider avoiding repeated addition of StreamHandlers.
If multiple instances of this client are created, this might attach multiple stream handlers to the same logger, leading to duplicated logs. You may wish to check if a handler is already present before adding a new one.def __init__(self, config: DeepgramClientOptions): self._logger = verboselogs.VerboseLogger(__name__) - self._logger.addHandler(logging.StreamHandler()) + if not self._logger.handlers: + self._logger.addHandler(logging.StreamHandler()) self._logger.setLevel(config.verbose) ...
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
deepgram/clients/auth/v1/__init__.py
(1 hunks)deepgram/clients/auth/v1/async_client.py
(1 hunks)deepgram/clients/auth/v1/client.py
(1 hunks)examples/auth/async_token/main.py
(1 hunks)examples/auth/token/main.py
(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
- deepgram/clients/auth/v1/init.py
- examples/auth/token/main.py
- deepgram/clients/auth/v1/client.py
- examples/auth/async_token/main.py
🧰 Additional context used
🧬 Code Graph Analysis (1)
deepgram/clients/auth/v1/async_client.py (3)
deepgram/options.py (1)
DeepgramClientOptions
(17-136)deepgram/clients/common/v1/abstract_async_rest.py (1)
AbstractAsyncRestClient
(16-383)deepgram/clients/auth/v1/response.py (1)
GrantTokenResponse
(13-24)
🔇 Additional comments (4)
deepgram/clients/auth/v1/async_client.py (4)
1-3
: License header looks good.
No concerns with the MIT license header and SPDX identifier.
5-10
: Imports appear well-organized.
All imported modules are relevant. No issues found with ordering or structure.
13-17
: Class docstring is clear and accurate.
It correctly describes this class as handling authentication endpoint requests.
31-52
:❓ Verification inconclusive
Verify the
DeepgramTypeError
reference.
The docstring mentionsDeepgramTypeError
, but there's no explicit import. Confirm thatAbstractAsyncRestClient
or another module properly raises it, or add an import if needed.
🏁 Script executed:
#!/bin/bash # Description: Confirm that DeepgramTypeError is defined/imported somewhere in the codebase. fd DeepgramTypeError --exec cat {}Length of output: 38
Below is a revised review comment:
Action Required: Verify the
DeepgramTypeError
ReferenceIt appears that no explicit definition or import of
DeepgramTypeError
was found anywhere in the repository. Please confirm whetherDeepgramTypeError
is intended to be provided by an upstream module (for example, via a base class likeAbstractAsyncRestClient
) or if an explicit import/definition should be added in this file. This will ensure that the docstring’s reference accurately reflects the available exception.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Had a question on the use of the AUDIO_URL variable in the examples, other than this looks good to me.
Proposed changes
Types of changes
What types of changes does your code introduce to the community Python SDK?
Put an
x
in the boxes that applyChecklist
Put an
x
in the boxes that apply. You can also fill these out after creating the PR. If you're unsure about any of them, don't hesitate to ask. We're here to help! This is simply a reminder of what we are going to look for before merging your code.Further comments
Summary by CodeRabbit