Adds support for OAuth 2.0
Hi maintainers,
Closes #102 .
This PR extends IBind's authentication capabilities by adding support for the OAuth 2.0 Client Credentials Grant flow. This complements the existing OAuth 1.0a implementation and further enables fully headless authentication with the IBKR Client Portal API. I've aimed to follow the project's contribution guidelines in preparing this feature.
Key changes include:
- A new
ibind.oauth.oauth2module withOAuth2Configfor configuration and logic for token management. - Integration of OAuth 2.0 into
IbkrClient, handling automatic SSO bearer token acquisition and session management. - Addition of new environment variables for OAuth 2.0 configuration, documented in the README.
- A new example script,
examples/rest_09_oauth2.py, to demonstrate practical usage. - An end-to-end test script,
test/e2e/test_ibind_oauth2.py(which loads credentials from a root.envfile), to verify the E2E functionality. - Updates to
README.mdwith information on OAuth 2.0 setup and usage. - Necessary updates to
pyproject.tomlandrequirements-dev.txtfor dependencies (pycryptodomefor core functionality,python-dotenvfor examples/dev). - The codebase for this PR has been formatted using Ruff.
Further Notes:
- This implementation provides the full end-to-end OAuth 2.0 functionality as demonstrated by the E2E test script. More granular unit tests for the OAuth module could be a future enhancement for the project.
- I used the official IBKR OAuth 2.0 setup guide for this implementation and can clarify details from it if helpful during the review process.
Please let me know if you have any questions or feedback. Thanks!
This is great! Thanks so much for putting the time and effort into this! Before I go deep and review the code itself, I'd like to understand how we can gain confidence in this change for IBind.
Things I'm curious about:
- What's the current IBKR pattern for OAuth2? Did you mention they have a support page for this now? Is it officially supported?
- How we as IBind maintainers plan to throughly test this as not all of us has an IBKR account that can support OAuth use
- What's the current DX for consumers to decide which OAuth to use? Did we just have a config for it? (Yes I understand it's probably defined in the code, but at a high level would like to know from requirements POV)
- What was your reasoning for using
pycryptodomevscryptography? We've talked about OAuth2 and even refactoring OAuth1 to usecryptographybecause it's has a dedicated security team, higher level constructs, pluspycryptodomemakes it easier for us to implement cryptography incorrectly
What do you think?
Hi Wes,
Thanks so much for taking a look and for the positive feedback! I'm happy to clarify these points:
- What's the current IBKR pattern for OAuth2? Did you mention they have a support page for this now? Is it officially supported?
- Yes, Interactive Brokers now officially supports OAuth 2.0 for authenticating with their Client Portal API, though it seems primarily targeted at their business users at this stage.
- I've been in touch with IBKR API Integration, and they've provided documentation and Postman collections outlining the specific OAuth 2.0 workflow. The general flow involves:
- Requesting an OAuth 2.0 Access Token (
/oauth2/api/v1/token). - Creating an SSO Session for the CP Web API (
/gw/api/v1/sso-sessions). - Validating the SSO Session (
/v1/api/sso/validate). - Initializing a brokerage session to access trading & market data (
/v1/api/iserver/auth/ssodh/init).
- Requesting an OAuth 2.0 Access Token (
- This implementation follows their guidelines. The successful execution of the end-to-end tests against their systems with this implementation gives us confidence that it aligns with their requirements.
Python Code I was sent: Websocket tester.txt Authentication.txt CP API tester.txt
-
How we as IBind maintainers plan to thoroughly test this as not all of us have an IBKR account that can support OAuth use?
- This is a valid concern. I've personally tested this implementation thoroughly with an OAuth 2.0 enabled account and am currently using this fork for my own applications that require it. The end-to-end test script (
test/e2e/test_ibind_oauth2.py) reflects these successful interactions.
- This is a valid concern. I've personally tested this implementation thoroughly with an OAuth 2.0 enabled account and am currently using this fork for my own applications that require it. The end-to-end test script (
-
What's the current DX for consumers to decide which OAuth to use? Did we just have a config for it?
-
Yes, the developer experience is designed to be consistent with how OAuth 1.0a is handled in
ibindand offers flexibility. -
To use OAuth 2.0, a consumer would initialize an
OAuth2Configobject. This can be done in two ways:- Explicitly: By passing credentials directly to the constructor:
from ibind import OAuth2Config oauth2_config_instance = OAuth2Config( client_id="YOUR_CLIENT_ID", client_key_id="YOUR_CLIENT_KEY_ID", private_key_pem="YOUR_PRIVATE_KEY_PEM_STRING", username="YOUR_IBKR_USERNAME" ) - Via Environment Variables: If the arguments are omitted,
OAuth2Config()will attempt to load the credentials from the following environment variables:IBIND_OAUTH2_CLIENT_IDIBIND_OAUTH2_CLIENT_KEY_IDIBIND_OAUTH2_PRIVATE_KEY_PEMIBIND_OAUTH2_USERNAME
- Explicitly: By passing credentials directly to the constructor:
-
Then, this
oauth_configinstance is passed to theIBKRClient:from ibind import IBKRClient # Assuming oauth2_config_instance is created as shown above client = IBKRClient(use_oauth=True, oauth_config=oauth2_config_instance) -
This mirrors the existing pattern for OAuth 1.0a. The
IBKRClientinspects the type of theoauth_configobject to determine which OAuth flow to use. -
The example script
examples/rest_09_oauth2.pydemonstrates initializingOAuth2Config(and loading from a.envfile, which sets up these environment variables) and then passing it toIBKRClient.
-
I hope this provides a clearer picture. This implementation has been working reliably for me, and I've aimed to align it closely with existing ibind patterns. Please let me know your further thoughts or any specific areas you'd like to discuss or see adjusted.
A separate shout out to @hughandersen who introduced the OAuth 1.0a and helped set up foundation for how this PR could be introduced.
Additionally, kudos to @janfrederik who's accurately deduced that OAuth 2.0 may soon become a viable option against my suggestions that it may not be the case - your comment helped us not having to rewrite a bunch of things right now, thanks and good foresight! π
Thanks @Voyz, the addition of OAuth 1.0a to your package seems to have been well received. Fyi OAuth 2.0 is easier to set up, and I believe IB will roll it out some time in the future.
A separate shout out to @hughandersen who introduced the OAuth 1.0a and helped set up foundation for how this PR could be introduced.
Additionally, kudos to @janfrederik who's accurately deduced that OAuth 2.0 may soon become a viable option against my suggestions that it may not be the case - your comment helped us not having to rewrite a bunch of things right now, thanks and good foresight! π
Thank you, @Voyz.
Thanks @Voyz, the addition of OAuth 1.0a to your package seems to have been well received. Fyi OAuth 2.0 is easier to set up, and I believe IB will roll it out some time in the future.
I hope they roll out that soon to individual accounts as well. oauth2 has been a while sitting there at IBKR...
Hi @Voyz and @weklund,
Thanks again for taking the time to provide such detailed feedback and for your insightful questions β it's really appreciated! I've pushed up some updates to this PR that I hope address everything you've raised. I've also merged in the latest from master to keep things current.
Addressing @weklund's questions:
- IBKR OAuth 2.0 Pattern & Support: This PR implements OAuth 2.0 using a server-to-server flow. To make configuration clear, there's now an
OAuth2Configdataclass where users can provide their credentials for this type of connection. - Testing by Maintainers: Totally understand the challenge here. As @Voyz mentioned, feedback from the community using this will be key. I've continued to run the end-to-end tests with my own OAuth 2.0 setup, and everything is passing after these latest changes.
- Developer Experience (Choosing OAuth Version): The choice of which OAuth version to use is now handled by the
IbkrClient'suse_oauthandoauth_configparameters:- If
use_oauthisFalse, no OAuth is used. - If
use_oauthisTrue:- Users will need to provide an
OAuth2Configinstance tooauth_configto use OAuth 2.0. - If they provide an
OAuth1aConfiginstance, the existing OAuth 1.0a flow will be used. - To make sure the configuration is explicit and correct, if
oauth_configisn't provided whenuse_oauthis true, an exception is now raised.
- Users will need to provide an
- If
Addressing @Voyz's feedback:
- Thanks again for the thorough review and the encouraging words! I've worked through your specific points.
- Logging Levels: Good call on the logging. I've gone through and changed most of the detailed operational logs in the OAuth 2.0 flow from
_LOGGER.infoto_LOGGER.debug._LOGGER.infois now used more for key user-facing events, as you suggested. - Specific Code Review Points & Refactoring: I've actioned your detailed comments. As you recommended, this involved a fair bit of refactoring in the core OAuth 2.0 logic:
- The OAuth 2.0 session initialization logic that was in
IbkrClienthas been pulled out into its own function (establish_oauth2_brokerage_session, which now lives inibind.oauth.oauth2.py). This new function has a more streamlined structure and less nesting. - I've also refactored
OAuth2Handlerto use the mainIbkrClientinstance's request methods and session. The idea here was to standardize how HTTP requests are made and ensure everything is consistent with the client's existing patterns for requests, logging, and error handling. The goal with these changes was to make the OAuth 2.0 integration clearer, more robust, and a better fit with the existing client structure.
- The OAuth 2.0 session initialization logic that was in
- Other improvements: Alongside those bigger refactoring pieces, I've also addressed other items from your review. For instance, OAuth dependency imports are now conditional (so users who don't need OAuth won't hit an
ImportError), URL parameter handling is more consistent, the_get_headersmethod is easier to read, I've added some helper methods toOAuth2Config(likehas_sso_bearer_token()), updated dataclass comments, and switched the E2E test script over to usepytestfixtures. I also made the necessary updates topyproject.tomland the example script regardingpython-dotenv.
Summary of Recent Changes:
- The branch is now up-to-date with
Voyz:master. - The core OAuth 2.0 logic for getting tokens and setting up the brokerage session has been significantly refactored, as detailed above.
- A number of smaller fixes and improvements, based on your review feedback, have been made in
IbkrClient,OAuth2Config, and the example script. - All end-to-end tests for the OAuth 2.0 flow are passing with these latest changes.
I think these updates cover the points from your review and help make the OAuth 2.0 support more solid. Let me know what you think, or if thereβs anything else!
Thanks!
@climbercarmich thanks for the great work! I'm already using OAuth1a and I'd also like to test your implementation of OAuth2: the question is how do I get required config parameters? Is there a process similar to OAuth1a setup (special IBKR page) or it's done purely via their support team?
hey @climbercarmich just wanted to follow up on this as this contribution is great and I wouldn't want it to get left behind - although I understand if you're unavailable at the moment to look into it more. I know I've left detailed PR reviews here, so if you'd need more help feel free to reach out to me at [email protected] and let's chat about how we could finalise this in more detail.
@art1c0 you have to contact IBKR support directly currently.
@Voyz sorry not had any spare time in the last month. Hopefully it will be possible for me to finish this contribution in July. Thanks for your detailed review too.
Dear ibind maintainer team, I would like to voice my support for a timely addition of oauth 2.
We have a ibkr business account with oauth 2 (setup through ibkr support email), we were also sent the same implementation examples: (Websocket tester.txt Authentication.txt CP API tester.txt)
Our internal implementation / fork matches @climbercarmich implementation ~90% and we would switch to the official implementation right away once it is merged.
hey @arau-j thanks for showing your support to this PR π It has been last reviewed in May but hasn't received further updates from its author - I'm assuming he's been busy and couldn't pick it up again. Should anyone feel like continuing their work, I'm happy to provide support and review further updates to this PR