Skip to content

Conversation

@lukeocodes
Copy link
Contributor

@lukeocodes lukeocodes commented Jun 21, 2025

Proposed changes

This PR adds comprehensive Bearer Token authentication support to the Deepgram Python SDK, enabling developers to use OAuth 2.0-compliant access tokens alongside the existing API key authentication.

Key Features:

  • Dual Authentication Support: Both Authorization: Token <API_KEY> and Authorization: Bearer <ACCESS_TOKEN>
  • Priority-based Credential Resolution: Access tokens take precedence when both are provided
  • Environment Variable Support: New DEEPGRAM_ACCESS_TOKEN alongside existing DEEPGRAM_API_KEY
  • Dynamic Authentication Switching: Runtime switching between authentication methods via set_access_token() and set_apikey()
  • Complete Workflow Example: Demonstrates API Key → grant_token() → Bearer Auth → API calls pattern
  • 100% Backward Compatibility: All existing code continues to work unchanged

Authentication Priority Order:

  1. Explicit access_token parameter (highest)
  2. Explicit api_key parameter
  3. DEEPGRAM_ACCESS_TOKEN environment variable
  4. DEEPGRAM_API_KEY environment variable (lowest)

This enables enhanced security workflows where developers can use long-lived API keys to obtain short-lived access tokens (30-second expiration) for improved security, scope limitation, and OAuth 2.0 compliance.

Additional Enhancement:

  • New examples/all.py script that auto-discovers and executes all SDK examples for comprehensive testing

Types of changes

What types of changes does your code introduce to the community Python SDK?
Put an x in the boxes that apply

  • Bugfix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update or tests (if none of the other choices apply)

Checklist

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.

  • I have read the CONTRIBUTING doc
  • I have lint'ed all of my code using repo standards
  • I have added tests that prove my fix is effective or that my feature works
  • I have added necessary documentation (if appropriate)

Further comments

Implementation Details:

This feature was implemented following SOLID principles with minimal changes to existing code paths. The core changes are concentrated in:

  1. deepgram/options.py: Added access_token parameter and set_access_token() method, enhanced _update_headers() logic
  2. deepgram/client.py: Extended constructor to accept and properly handle access tokens with environment fallbacks
  3. Authentication Priority: Access tokens take precedence over API keys when both are provided, ensuring predictable behavior

Testing Strategy:

  • 31 comprehensive unit tests covering header generation, credential priority, environment variable resolution, authentication switching, and error handling
  • Backward compatibility verified by testing 27+ existing examples - all continue to work unchanged
  • Real-world workflow testing with actual API calls demonstrating the complete bearer token lifecycle

Example Usage:

# Method 1: Direct access token usage client = DeepgramClient(access_token="your-access-token") # Method 2: API Key → Access Token workflow  api_client = DeepgramClient(api_key="your-api-key") token_response = api_client.auth.v("1").grant_token() bearer_client = DeepgramClient(access_token=token_response.access_token) # Method 3: Environment variables # DEEPGRAM_ACCESS_TOKEN=your-token client = DeepgramClient() # Auto-detects access token

The implementation maintains the SDK's clean, intuitive API while providing the flexibility needed for modern authentication workflows. The examples/auth/bearer_token_demo/main.py demonstrates the complete practical usage pattern that developers will likely adopt.

Summary by CodeRabbit

  • New Features

    • Added support for authentication using either API keys or access tokens, with access tokens taking precedence if both are provided.
    • Introduced a new example script demonstrating authentication with a bearer token and its usage in audio transcription.
    • Added a script to automate running all example scripts.
  • Documentation

    • Updated the README with detailed instructions and examples for both API key and access token authentication methods.
  • Bug Fixes

    • Improved handling and prioritization of authentication credentials, ensuring correct header generation and error handling.
    • Aligned default model option values to use None instead of the string "None" for consistency.
  • Tests

    • Added comprehensive unit tests covering authentication scenarios, credential precedence, environment variable resolution, and error conditions.
    • Refined daily tests for WebSocket transcription to focus on message receipt and structure validation rather than exact transcript matching.
  • Chores

    • Updated .gitignore to exclude test audio artifacts.
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jun 21, 2025

Walkthrough

This update introduces support for both API key and access token authentication in the Deepgram Python SDK, updating client initialization logic, configuration handling, and documentation. It adds comprehensive unit tests for authentication mechanisms, a bearer token authentication example, and a script to run all examples. The .gitignore is updated to exclude test audio artifacts.

Changes

File(s) Change Summary
.gitignore Added ignore patterns for test audio artifacts (output.wav, test.mp3) under a new "test artifacts" section.
README.md Added detailed "Authentication" section covering API key and access token usage, with examples and environment variable documentation. Added extensive new sections including migration guides, initialization, streaming, voice agent, text to speech, text intelligence, projects, keys, members, scopes, invitations, usage, billing, models, on-prem APIs, pinning versions, logging, testing, backwards compatibility, and development guidelines. Minor badge URL and formatting fixes.
deepgram/client.py, deepgram/options.py Refactored client and options to support both API key and access token authentication. Updated credential resolution logic, header generation, and added new methods for setting credentials. Updated docstrings and public attributes accordingly.
examples/all.py Introduced a new script to discover, filter, and sequentially execute all example scripts, reporting results and handling errors.
examples/auth/bearer_token_demo/main.py Added a new example demonstrating authentication with both API key and bearer token, including obtaining a token and performing a transcription request.
tests/unit_test/test_unit_authentication.py Introduced comprehensive unit tests for authentication logic, covering header generation, credential precedence, environment variable handling, dynamic updates, error conditions, and grant token workflows.
deepgram/clients/listen/v1/rest/options.py Changed default model field value in PrerecordedOptions from string "None" to actual None.
deepgram/clients/listen/v1/websocket/options.py Changed default model field value in LiveOptions from string "None" to actual None.
tests/daily_test/test_daily_async_listen_websocket.py Refactored test to remove expected transcript output matching, focusing on receipt and structure validation of transcript messages.
tests/daily_test/test_daily_listen_websocket.py Refactored test to remove expected transcript output matching, focusing on receipt and structure validation of transcript messages.
tests/response_data/listen/websocket/* Added new JSON test data files with audio options, responses, and command references for websocket audio transcription tests.
tests/response_data/listen/rest/* Updated several JSON test response files with new request IDs, timestamps, and minor content refinements in transcripts and summaries.
Miscellaneous minor formatting and newline additions Reformatted import statements, multi-line calls, string quote styles, and added newlines at file ends in various example and client files without logic changes.

Sequence Diagram(s)

sequenceDiagram participant User participant DeepgramClient participant DeepgramAPI User->>DeepgramClient: Initialize (api_key and/or access_token) alt access_token provided DeepgramClient->>DeepgramClient: Set Authorization header (Bearer) else api_key provided DeepgramClient->>DeepgramClient: Set Authorization header (Token) else DeepgramClient->>User: Warn/raise error (no credentials) end User->>DeepgramClient: Request grant_token (with API key) DeepgramClient->>DeepgramAPI: POST /auth/token DeepgramAPI-->>DeepgramClient: Return access_token User->>DeepgramClient: Initialize new client with access_token DeepgramClient->>DeepgramClient: Set Authorization header (Bearer) User->>DeepgramClient: Transcribe audio DeepgramClient->>DeepgramAPI: POST /listen (with Bearer token) DeepgramAPI-->>DeepgramClient: Return transcript DeepgramClient-->>User: Transcript result 
Loading

Possibly related PRs

Suggested labels

documentation

Suggested reviewers

  • naomi-lgbt
  • jpvajda

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 Pylint (3.3.7)
deepgram/client.py
tests/unit_test/test_unit_authentication.py
deepgram/options.py
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate Unit Tests
  • Create PR with Unit Tests
  • Post Copyable Unit Tests in Comment
  • Commit Unit Tests in branch lo/bearer-auth-token

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

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)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai auto-generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (3)
README.md (1)

125-125: Fix typo in the word "abstract".

There's a typo in the word "abtract" which should be "abstract".

-This SDK aims to reduce complexity and abtract/hide some internal Deepgram details that clients shouldn't need to know about. However you can still tweak options and settings if you need. +This SDK aims to reduce complexity and abstract/hide some internal Deepgram details that clients shouldn't need to know about. However, you can still tweak options and settings if you need.
examples/all.py (1)

140-142: Consider option to continue on failures for comprehensive testing.

The script currently stops on the first failure, which might prevent discovering issues in other examples. Consider adding a --continue-on-error flag for comprehensive testing scenarios.

# Add argument parsing for continue-on-error option import argparse def main(): parser = argparse.ArgumentParser() parser.add_argument('--continue-on-error', action='store_true', help='Continue running examples even if some fail') args = parser.parse_args() # Later in the loop: if not success and not args.continue_on_error: print(f"\n🛑 Stopping execution due to failure in: {script}") break
deepgram/options.py (1)

141-142: Consider separating unrelated improvements.

While these float conversions improve robustness, they're unrelated to the authentication feature. Consider keeping PRs focused on a single concern for easier review and git history.

Also applies to: 152-153

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a2d66fe and d8faa4b.

📒 Files selected for processing (7)
  • .gitignore (1 hunks)
  • README.md (3 hunks)
  • deepgram/client.py (12 hunks)
  • deepgram/options.py (11 hunks)
  • examples/all.py (1 hunks)
  • examples/auth/bearer_token_demo/main.py (1 hunks)
  • tests/unit_test/test_unit_authentication.py (1 hunks)
🧰 Additional context used
🪛 LanguageTool
README.md

[uncategorized] ~78-~78: Loose punctuation mark.
Context: ...ronment variables: - DEEPGRAM_API_KEY: Your Deepgram API key - `DEEPGRAM_ACCES...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~125-~125: A comma may be missing after the conjunctive/linking adverb ‘However’.
Context: ...t clients shouldn't need to know about. However you can still tweak options and setting...

(SENT_START_CONJUNCTIVE_LINKING_ADVERB_COMMA)

🔇 Additional comments (12)
.gitignore (1)

28-30: LGTM - Appropriate test artifact exclusions.

The addition of test audio artifacts to .gitignore is correct and prevents accidentally committing generated files from examples and tests.

README.md (1)

32-82: Excellent authentication documentation.

The new Authentication section clearly documents both authentication methods with comprehensive examples. The precedence rules are well explained, making it easy for users to understand how credentials are resolved.

examples/auth/bearer_token_demo/main.py (1)

23-65: Excellent authentication workflow demonstration.

The example clearly demonstrates the complete API key to bearer token workflow with good error handling and informative logging. The 4-step process is well-documented and easy to follow.

examples/all.py (1)

19-94: Excellent example discovery and execution framework.

The script provides a robust framework for discovering and running examples with smart filtering, real-time output streaming, and comprehensive error handling. The separation into well-named functions makes it maintainable and easy to understand.

deepgram/client.py (3)

417-417: Clear documentation updates for dual authentication.

The docstring updates clearly reflect the new dual authentication support and error conditions.

Also applies to: 421-421


446-485: Excellent authentication credential resolution logic.

The implementation correctly handles credential precedence with a clear waterfall approach:

  1. Explicit parameters (access_token preferred over api_key)
  2. Config object credentials
  3. Environment variables (DEEPGRAM_ACCESS_TOKEN before DEEPGRAM_API_KEY)
  4. Appropriate warnings for missing credentials

The code maintains backward compatibility while properly supporting the new authentication method.


463-465: ```shell
#!/bin/bash
grep -R "Neither API key nor access token is provided" -n deepgram/client.py || echo "Not found"

 </details> <details> <summary>deepgram/options.py (4)</summary> `25-61`: **Well-implemented authentication parameter additions.** The constructor changes properly handle the new `access_token` parameter with appropriate None checks and documentation. The custom header preservation logic is a thoughtful addition that ensures user-defined headers aren't lost during authentication updates. --- `84-96`: **Correct implementation of mutually exclusive authentication methods.** The `set_apikey` and `set_access_token` methods properly maintain mutual exclusivity by clearing the alternate credential. The symmetric implementation ensures consistent behavior. --- `103-127`: **Excellent header management with proper authentication priority.** The refactored `_update_headers` method correctly implements: - Custom header preservation for non-system headers - Access token priority over API key as documented - Proper Bearer/Token prefixes for different authentication types --- `199-212`: **Correct implementation of environment variable priority.** The credential loading logic properly implements the documented priority order with `DEEPGRAM_ACCESS_TOKEN` taking precedence over `DEEPGRAM_API_KEY`. The error handling ensures users provide at least one form of authentication. </details> <details> <summary>tests/unit_test/test_unit_authentication.py (1)</summary> `1-443`: **Excellent comprehensive test coverage for authentication features.** This test suite thoroughly validates all aspects of the new authentication functionality: - Correct Authorization header formats (Token/Bearer) - Credential priority across different initialization methods - Environment variable resolution and precedence - Dynamic credential switching behavior - Error handling scenarios - Complete API key to access token workflow The tests are well-organized, follow good naming conventions, and provide confidence in the implementation's correctness. </details> </blockquote></details> </details> <!-- This is an auto-generated comment by CodeRabbit for review status --> 
Copy link
Contributor

@coderabbitai coderabbitai bot left a 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 (4)
README.md (4)

11-11: TOC: Remove unnecessary escaping in ‘V3. to V4’.*
The backslash before the asterisk is not needed and may break the Markdown link anchor.

Apply:

- - [V3.\*\ to V4](#v3-to-v4) + - [V3.* to V4](#v3-to-v4)

83-85: Refine migration guide wording for clarity.
Change “on our docs” to “in our documentation” for formality and consistency:

- We have published [a migration guide on our docs](…) + We have published [a migration guide in our documentation](…)

93-93: Installation prompt: simplify wording.
Consider dropping “available” for brevity:

- To install the latest version available: + To install the latest version:

101-101: Conciseness: remove “of” in sentence.
Refactor for brevity:

- All of the examples below will require `DeepgramClient`. + The examples below require `DeepgramClient`.
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d8faa4b and 5c7d3e9.

📒 Files selected for processing (1)
  • README.md (4 hunks)
🧰 Additional context used
🪛 LanguageTool
README.md

[duplication] ~10-~10: Possible typo: you repeated a word.
Context: ...ating-from-earlier-versions) - V2 to V3 - V3.*\ to V4 - [Requirements](...

(ENGLISH_WORD_REPEAT_RULE)


[grammar] ~31-~31: This phrase is duplicated. You should probably use “Projects Get” only once.
Context: ...ils) - Grant Token - Projects - Get Projects - Get Project - [Update Proj...

(PHRASE_REPETITION)


[style] ~100-~100: Consider removing “of” to be more concise
Context: ...ll deepgram-sdk ``` ## Initialization All of the examples below will require `DeepgramCl...

(ALL_OF_THE)


[uncategorized] ~112-~112: Possible missing comma found.
Context: ...g an API Key 🔑 To access the Deepgram API you will need a [free Deepgram API Key]...

(AI_HYDRA_LEO_MISSING_COMMA)


[grammar] ~397-~397: This phrase is duplicated. You should probably use “environment variable” only once.
Context: ...arameter** 3. DEEPGRAM_ACCESS_TOKEN environment variable 4. DEEPGRAM_API_KEY environment variable (lowest priority) ### Environment Va...

(PHRASE_REPETITION)


[style] ~568-~568: Consider removing “of” to be more concise
Context: ... Members Retrieves account objects for all of the accounts in the specified project_id. ...

(ALL_OF_THE)


[style] ~778-~778: Consider a different adjective to strengthen your wording.
Context: ...ide) if you'd like to learn more. For a deeper understanding of how version numbers wo...

(DEEP_PROFOUND)


[uncategorized] ~780-~780: Possible missing comma found.
Context: ...ts.txtfile, you can pin to a specific version like this: ```sh deepgram-sdk==4.1.0...

(AI_HYDRA_LEO_MISSING_COMMA)


[style] ~794-~794: To make your writing clearer, consider a more direct alternative.
Context: ... ## Logging This SDK provides logging as a means to troubleshoot and debug issues encountered. By defaul...

(AS_A_MEANS_TO)


[style] ~794-~794: In American English, abbreviations like “etc.” require a period.
Context: ...ages and higher (ie Warning, Error, etc) when you initialize the library as fol...

(ETC_PERIOD)


[uncategorized] ~839-~839: Use a comma before ‘so’ if it connects two independent clauses (unless they are closely connected and short).
Context: ... we will maintain backward compatibility so your code will continue to work without...

(COMMA_COMPOUND_SENTENCE_2)


[style] ~850-~850: Consider a more concise word here.
Context: ...G.md) guidelines for more information. In order to develop new features for the SDK itself...

(IN_ORDER_TO_PREMIUM)

🔇 Additional comments (7)
README.md (7)

3-3: Verify badge URLs and styling consistency.
Ensure the new Discord, CI, and PyPI badges render correctly and link to the intended resources.


9-10: TOC: Migrating section entries look good.
The new “Migrating from earlier versions” and its sub-entries correctly reflect the added section.


14-15: TOC: Initialization entries are correct.
Initialization and “Getting an API Key” links correctly point to the new section.


28-31: TOC: Authentication entries added.
The new “Authentication” section and its token sub-entries are now discoverable in the table of contents.


77-81: Add “Migrating from earlier versions” section.
The new headers and structure for V2→V3 and V3→V4 migrations match the PR objectives.


99-99: Initialization header placement.
The new “## Initialization” header correctly introduces the client setup examples.


104-104: Import statement for client initialization.
The sample from deepgram import DeepgramClient import aligns with the new dual-auth API.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🔭 Outside diff range comments (1)
tests/daily_test/test_daily_listen_websocket.py (1)

1-177: Consider extracting common test logic to reduce duplication.

This file is nearly identical to test_daily_async_listen_websocket.py except for async/await keywords. Consider extracting the common test logic into a shared base class or utility functions.

Create a shared test utilities module:

# tests/daily_test/websocket_test_utils.py def create_test_state(): return { "transcript_received": False, "message_structure_valid": False, "raw_json": "" } def validate_message_structure(result, test_state): """Common message validation logic.""" try: # Check if we can access the transcript (validates structure) transcript = result.channel.alternatives[0].transcript # Validate that essential fields exist assert hasattr(result, 'channel'), "Result should have channel field" assert hasattr(result, 'is_final'), "Result should have is_final field" assert hasattr(result, 'metadata'), "Result should have metadata field" assert hasattr(result.channel, 'alternatives'), "Channel should have alternatives" assert len(result.channel.alternatives) > 0, "Should have at least one alternative" test_state["message_structure_valid"] = True test_state["raw_json"] = result.to_json() test_state["transcript_received"] = True except (AttributeError, IndexError, AssertionError) as e: print(f"Message structure validation failed: {type(e).__name__}: {e}") test_state["message_structure_valid"] = False def generate_test_filenames(unique): """Generate test file paths.""" return { "cmd": f"tests/response_data/listen/websocket/{unique}.cmd", "options": f"tests/response_data/listen/websocket/{unique}-options.json", "resp": f"tests/response_data/listen/websocket/{unique}-response.json", "error": f"tests/response_data/listen/websocket/{unique}-error.json" }

This would significantly reduce code duplication and make maintenance easier.

♻️ Duplicate comments (5)
tests/daily_test/test_daily_listen_websocket.py (4)

22-22: Remove unused MODEL variable.


122-124: Use specific exception types for better error diagnostics.


150-150: Fix spacing in slice notation.


54-65: Replace global variables with local test state.

Same issue as in the async version - global variables can cause race conditions.

Also applies to: 97-97

tests/unit_test/test_unit_authentication.py (1)

183-193: Related to environment variable priority issue

This test also expects DEEPGRAM_API_KEY to take precedence over DEEPGRAM_ACCESS_TOKEN, which appears to contradict the documented priority order in the PR objectives.

🧹 Nitpick comments (5)
tests/daily_test/test_daily_async_listen_websocket.py (3)

22-22: Remove unused MODEL variable.

The MODEL variable is defined but never used in the test.

-MODEL = "general-nova-3" -

123-125: Consider catching specific exceptions for better error diagnostics.

The broad Exception catch might hide specific validation errors that could provide better diagnostics.

- except Exception as e: - print(f"Message structure validation failed: {e}") - message_structure_valid = False + except (AttributeError, IndexError, AssertionError) as e: + print(f"Message structure validation failed: {type(e).__name__}: {e}") + message_structure_valid = False + except Exception as e: + print(f"Unexpected error during message validation: {type(e).__name__}: {e}") + message_structure_valid = False + raise # Re-raise unexpected exceptions for better debugging

150-150: Fix inconsistent spacing in slice notation.

- chunk = data[i: i + chunk_size].tobytes() + chunk = data[i:i + chunk_size].tobytes()
tests/unit_test/test_unit_authentication.py (2)

292-292: Remove unused import

The logging module is imported but not used in this test method.

- import logging - with patch('deepgram.client.verboselogs.VerboseLogger') as mock_logger:

1-446: Consider adding edge case tests

While the test coverage is comprehensive, consider adding tests for these edge cases:

  1. Thread safety of credential switching in concurrent scenarios
  2. Behavior when switching credentials during active API calls
  3. Token expiration handling scenarios

Would you like me to generate additional test cases for these scenarios?

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 08d5eac and ab20831.

⛔ Files ignored due to path filters (1)
  • tests/response_data/speak/rest/18144fa7f4709bc9972c24d0addc8faa360dca933e7e0027b062e57b7c41f426-f8c3bf62a9aa3e6fc1619c250e48abe7519373d3edf41be62eb5dc45199af2ef.wav is excluded by !**/*.wav
📒 Files selected for processing (13)
  • deepgram/client.py (12 hunks)
  • deepgram/clients/listen/v1/rest/options.py (1 hunks)
  • deepgram/clients/listen/v1/websocket/options.py (1 hunks)
  • deepgram/options.py (11 hunks)
  • tests/daily_test/test_daily_async_listen_websocket.py (4 hunks)
  • tests/daily_test/test_daily_listen_websocket.py (4 hunks)
  • tests/response_data/listen/websocket/ed5bfd217988aa8cad492f63f79dc59f5f02fb9b85befe6f6ce404b8f19aaa0d-42fc5ed98cabc1fa1a2f276301c27c46dd15f6f5187cd93d944cc94fa81c8469-options.json (1 hunks)
  • tests/response_data/listen/websocket/ed5bfd217988aa8cad492f63f79dc59f5f02fb9b85befe6f6ce404b8f19aaa0d-42fc5ed98cabc1fa1a2f276301c27c46dd15f6f5187cd93d944cc94fa81c8469-response.json (1 hunks)
  • tests/response_data/listen/websocket/ed5bfd217988aa8cad492f63f79dc59f5f02fb9b85befe6f6ce404b8f19aaa0d-42fc5ed98cabc1fa1a2f276301c27c46dd15f6f5187cd93d944cc94fa81c8469.cmd (1 hunks)
  • tests/response_data/listen/websocket/ed5bfd217988aa8cad492f63f79dc59f5f02fb9b85befe6f6ce404b8f19aaa0d-d7334c26cf6468c191e05ff5e8151da9b67985c66ab177e9446fd14bbafd70df-options.json (1 hunks)
  • tests/response_data/listen/websocket/ed5bfd217988aa8cad492f63f79dc59f5f02fb9b85befe6f6ce404b8f19aaa0d-d7334c26cf6468c191e05ff5e8151da9b67985c66ab177e9446fd14bbafd70df-response.json (1 hunks)
  • tests/response_data/listen/websocket/ed5bfd217988aa8cad492f63f79dc59f5f02fb9b85befe6f6ce404b8f19aaa0d-d7334c26cf6468c191e05ff5e8151da9b67985c66ab177e9446fd14bbafd70df.cmd (1 hunks)
  • tests/unit_test/test_unit_authentication.py (1 hunks)
✅ Files skipped from review due to trivial changes (8)
  • tests/response_data/listen/websocket/ed5bfd217988aa8cad492f63f79dc59f5f02fb9b85befe6f6ce404b8f19aaa0d-d7334c26cf6468c191e05ff5e8151da9b67985c66ab177e9446fd14bbafd70df-options.json
  • tests/response_data/listen/websocket/ed5bfd217988aa8cad492f63f79dc59f5f02fb9b85befe6f6ce404b8f19aaa0d-42fc5ed98cabc1fa1a2f276301c27c46dd15f6f5187cd93d944cc94fa81c8469-options.json
  • deepgram/clients/listen/v1/rest/options.py
  • tests/response_data/listen/websocket/ed5bfd217988aa8cad492f63f79dc59f5f02fb9b85befe6f6ce404b8f19aaa0d-d7334c26cf6468c191e05ff5e8151da9b67985c66ab177e9446fd14bbafd70df.cmd
  • deepgram/clients/listen/v1/websocket/options.py
  • tests/response_data/listen/websocket/ed5bfd217988aa8cad492f63f79dc59f5f02fb9b85befe6f6ce404b8f19aaa0d-42fc5ed98cabc1fa1a2f276301c27c46dd15f6f5187cd93d944cc94fa81c8469-response.json
  • tests/response_data/listen/websocket/ed5bfd217988aa8cad492f63f79dc59f5f02fb9b85befe6f6ce404b8f19aaa0d-42fc5ed98cabc1fa1a2f276301c27c46dd15f6f5187cd93d944cc94fa81c8469.cmd
  • tests/response_data/listen/websocket/ed5bfd217988aa8cad492f63f79dc59f5f02fb9b85befe6f6ce404b8f19aaa0d-d7334c26cf6468c191e05ff5e8151da9b67985c66ab177e9446fd14bbafd70df-response.json
🚧 Files skipped from review as they are similar to previous changes (2)
  • deepgram/client.py
  • deepgram/options.py
🔇 Additional comments (3)
tests/unit_test/test_unit_authentication.py (3)

15-21: LGTM!

This test correctly verifies that API keys generate the expected Token authorization header format.


207-222: Well-structured auth switching test

This test properly verifies the authentication switching behavior, including the important detail that the previous credential is cleared when switching auth methods.


351-389: Excellent workflow test coverage

This test comprehensively validates the complete API key to access token workflow, properly mocking the grant token response and verifying each step of the process.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🔭 Outside diff range comments (1)
tests/unit_test/test_unit_authentication.py (1)

445-446: Incomplete assertion statement.

Line 446 has an assertion that appears incomplete or incorrectly formatted. It's missing the expected value comparison.

The assertion should be properly formatted:

- assert api_client._config.api_key != bearer_client._config.access_token + assert api_client._config.api_key != bearer_client._config.access_token

If this was intended to verify the values are different, consider adding a more descriptive assertion message:

- assert api_client._config.api_key != bearer_client._config.access_token + assert api_client._config.api_key != bearer_client._config.access_token, \ + "API key and access token should be different"
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c7dc37c and d473df6.

⛔ Files ignored due to path filters (1)
  • tests/response_data/speak/rest/1fe0ad339338a9d6cffbab2c7ace41ba5387b5fe7906854795702dce91034fd3-f8c3bf62a9aa3e6fc1619c250e48abe7519373d3edf41be62eb5dc45199af2ef.wav is excluded by !**/*.wav
📒 Files selected for processing (12)
  • deepgram/client.py (12 hunks)
  • deepgram/options.py (10 hunks)
  • tests/response_data/listen/rest/a231370d439312b1a404bb6ad8de955e900ec8eae9a906329af8cc672e6ec7ba-29e7c8100617f70da4ae9da1921cb5071a01219f4780ca70930b0a370ed2163a-response.json (1 hunks)
  • tests/response_data/listen/rest/a231370d439312b1a404bb6ad8de955e900ec8eae9a906329af8cc672e6ec7ba-a17f4880c5b4cf124ac54d06d77c9f0ab7f3fe1052ff1c7b090f7eaf8ede5b76-response.json (1 hunks)
  • tests/response_data/listen/rest/c4e1c0031174878d8f0e3dbd87916ee16d56f1c610ac525af5712ea37226a455-29e7c8100617f70da4ae9da1921cb5071a01219f4780ca70930b0a370ed2163a-response.json (1 hunks)
  • tests/response_data/listen/rest/c4e1c0031174878d8f0e3dbd87916ee16d56f1c610ac525af5712ea37226a455-a17f4880c5b4cf124ac54d06d77c9f0ab7f3fe1052ff1c7b090f7eaf8ede5b76-response.json (1 hunks)
  • tests/response_data/listen/websocket/ed5bfd217988aa8cad492f63f79dc59f5f02fb9b85befe6f6ce404b8f19aaa0d-42fc5ed98cabc1fa1a2f276301c27c46dd15f6f5187cd93d944cc94fa81c8469-response.json (1 hunks)
  • tests/response_data/listen/websocket/ed5bfd217988aa8cad492f63f79dc59f5f02fb9b85befe6f6ce404b8f19aaa0d-d7334c26cf6468c191e05ff5e8151da9b67985c66ab177e9446fd14bbafd70df-response.json (1 hunks)
  • tests/response_data/read/rest/3917a1c81c08e360c0d4bba0ff9ebd645e610e4149483e5f2888a2c5df388b37-23e873efdfd4d680286fda14ff8f10864218311e79efc92ecc82bce3e574c366-error.json (1 hunks)
  • tests/response_data/read/rest/3917a1c81c08e360c0d4bba0ff9ebd645e610e4149483e5f2888a2c5df388b37-23e873efdfd4d680286fda14ff8f10864218311e79efc92ecc82bce3e574c366-response.json (1 hunks)
  • tests/response_data/speak/rest/1fe0ad339338a9d6cffbab2c7ace41ba5387b5fe7906854795702dce91034fd3-f8c3bf62a9aa3e6fc1619c250e48abe7519373d3edf41be62eb5dc45199af2ef-response.json (1 hunks)
  • tests/unit_test/test_unit_authentication.py (1 hunks)
✅ Files skipped from review due to trivial changes (3)
  • tests/response_data/read/rest/3917a1c81c08e360c0d4bba0ff9ebd645e610e4149483e5f2888a2c5df388b37-23e873efdfd4d680286fda14ff8f10864218311e79efc92ecc82bce3e574c366-error.json
  • tests/response_data/read/rest/3917a1c81c08e360c0d4bba0ff9ebd645e610e4149483e5f2888a2c5df388b37-23e873efdfd4d680286fda14ff8f10864218311e79efc92ecc82bce3e574c366-response.json
  • tests/response_data/listen/rest/a231370d439312b1a404bb6ad8de955e900ec8eae9a906329af8cc672e6ec7ba-29e7c8100617f70da4ae9da1921cb5071a01219f4780ca70930b0a370ed2163a-response.json
🚧 Files skipped from review as they are similar to previous changes (8)
  • tests/response_data/speak/rest/1fe0ad339338a9d6cffbab2c7ace41ba5387b5fe7906854795702dce91034fd3-f8c3bf62a9aa3e6fc1619c250e48abe7519373d3edf41be62eb5dc45199af2ef-response.json
  • tests/response_data/listen/rest/c4e1c0031174878d8f0e3dbd87916ee16d56f1c610ac525af5712ea37226a455-29e7c8100617f70da4ae9da1921cb5071a01219f4780ca70930b0a370ed2163a-response.json
  • tests/response_data/listen/rest/c4e1c0031174878d8f0e3dbd87916ee16d56f1c610ac525af5712ea37226a455-a17f4880c5b4cf124ac54d06d77c9f0ab7f3fe1052ff1c7b090f7eaf8ede5b76-response.json
  • tests/response_data/listen/websocket/ed5bfd217988aa8cad492f63f79dc59f5f02fb9b85befe6f6ce404b8f19aaa0d-42fc5ed98cabc1fa1a2f276301c27c46dd15f6f5187cd93d944cc94fa81c8469-response.json
  • tests/response_data/listen/rest/a231370d439312b1a404bb6ad8de955e900ec8eae9a906329af8cc672e6ec7ba-a17f4880c5b4cf124ac54d06d77c9f0ab7f3fe1052ff1c7b090f7eaf8ede5b76-response.json
  • tests/response_data/listen/websocket/ed5bfd217988aa8cad492f63f79dc59f5f02fb9b85befe6f6ce404b8f19aaa0d-d7334c26cf6468c191e05ff5e8151da9b67985c66ab177e9446fd14bbafd70df-response.json
  • deepgram/client.py
  • deepgram/options.py
🔇 Additional comments (2)
tests/unit_test/test_unit_authentication.py (2)

12-62: Well-structured test coverage for header generation.

The TestHeaderGeneration class provides comprehensive coverage for all authentication header scenarios, including API key ("Token") and access token ("Bearer") formats, as well as edge cases with empty or missing credentials.


289-302: ```shell
#!/bin/bash

Inspect deepgram/client.py for logger imports and usage

FILE="deepgram/client.py"

echo "1) Checking for verboselogs references:"
rg -n "verboselogs" "$FILE" || echo "No verboselogs references found."

echo -e "\n2) Checking for self._logger instantiation:"
rg -n "self._logger" "$FILE" || echo "No self._logger references found."

echo -e "\n3) Showing excerpts around init method for DeepgramClient:"

Find the line where the class starts

START_LINE=$(rg -n "class DeepgramClient" --max-count 1 "$FILE" | cut -d: -f1)

Print the next 60 lines after class declaration

if [ -n "$START_LINE" ]; then
sed -n "${START_LINE},$((START_LINE+60))p" "$FILE"
else
echo "Could not locate DeepgramClient class declaration."
fi

 </details> </blockquote></details> </details> <!-- This is an auto-generated comment by CodeRabbit for review status --> 
@lukeocodes lukeocodes merged commit 1200c83 into main Jun 24, 2025
6 checks passed
@lukeocodes lukeocodes deleted the lo/bearer-auth-token branch June 24, 2025 13:19
@jjmaldonis
Copy link
Contributor

jjmaldonis commented Jun 24, 2025

This PR review is late, but it looks good.

My only question is: What's the intended use case for tokens, and does the implementation (and example) reflect that use case?

For example, I'm surprised that creating a new DeepgramClient with a 30-second JWT token is the recommended way to use access tokens. It seems like a lot of overhead to create a new DeepgramClient every 30 seconds simply because the access token expires.

Should the user be applying the set_access_token method instead? If so, the code defaults to using an API key rather than an access token, so will the access token ever actually be used?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

4 participants