-
Notifications
You must be signed in to change notification settings - Fork 113
Two Factor Authentication
While the Gateway doesn't support any interface for two-factor authentication (2FA), IBeam provides a method for attempting to complete the 2FA in various forms.
It is done by stopping the authentication process while the 2FA request is detected and launching a callback which will acquire the 2FA code and return it back to authentication process. Upon receiving a correct code, IBeam will input it into the 2FA form and continue with the authentication.
Currently, there are two built-in handlers for 2FA, however IBeam also allows you to provide your own custom 2FA handler using Inputs Directory.
You can select which handler you want to use by setting the IBEAM_TWO_FA_HANDLER
environment variable to:
-
GOOGLE_MSG
- for Google Messages Handler -
EXTERNAL_REQUEST
- for External Request Handler -
CUSTOM_HANDLER
- for Custom 2FA Handler
IBeam comes with two built-in 2FA handlers:
- Google Messages Handler - acquiring the code from an SMS at Google Messages
- External Request Handler - acquiring the code through an external HTTP request
- Set
IBEAM_TWO_FA_HANDLER
toGOOGLE_MSG
. - Open Google Messages app and tap settings (⋮) menu at the top right.
- Tap "Messages for web" and then "QR code scanner"
- Run IBeam and you will be presented with a URL to a QR code.
- Open the URL in a browser and scan the resulting QR code with your phone.
Google Messages can be used to receive the 2FA SMS code.
When IBeam first runs with this handler, it will generate a unique URL that you need to access to complete the Google Messages registration.
From then on, upon 2FA request IBeam will access that Google Messages account and read the most recent SMS, content of which will be parsed for the 2FA code.
The integration functions by looking for an "unread" (bolded) message on your phone with a verification code from Interactive Brokers. If you accidentally read/open this message using your phone before IBeam finds it, you will have to wait for the timeout and second attempt.
- Set
IBEAM_TWO_FA_HANDLER
toEXTERNAL_REQUEST
. - Expects any 2FA method.
External Request Handler will request the code from an external server using HTTP. It is expected that you have a form of acquiring the 2FA code independently of IBeam.
You can provide the following environment variables for the HTTP request:
Variable name | Default value | Description |
---|---|---|
IBEAM_EXTERNAL_REQUEST_METHOD |
GET | Method to use by the external request 2FA handler. |
IBEAM_EXTERNAL_REQUEST_URL |
None | URL to use by the external request 2FA handler. |
IBEAM_EXTERNAL_REQUEST_TIMEOUT |
300 | Timeout for the external 2FA request. |
IBEAM_EXTERNAL_REQUEST_PARAMS |
None | JSON-formatted URL params to use by the external request 2FA handler. |
IBEAM_EXTERNAL_REQUEST_DATA |
None | JSON-formatted POST data to use by the external request 2FA handler. |
IBEAM_EXTERNAL_REQUEST_HEADERS |
None | JSON-formatted headers to use by the external request 2FA handler. |
For example:
-
IBEAM_EXTERNAL_REQUEST_METHOD
: POST -
IBEAM_EXTERNAL_REQUEST_URL
: https://my-example-server.com/ibkr-two-fa -
IBEAM_EXTERNAL_REQUEST_TIMEOUT
: 120 -
IBEAM_EXTERNAL_REQUEST_PARAMS
: {"example_url_param": "example_param_value"} -
IBEAM_EXTERNAL_REQUEST_DATA
: {"example_post_data": "example_data_value"} -
IBEAM_EXTERNAL_REQUEST_HEADERS
: {"Content-Type": "application/json"}
- Set
IBEAM_TWO_FA_HANDLER
toCUSTOM_HANDLER
to use it. - Expects any 2FA method.
IBeam supports using your own custom 2FA handler class provided through the Inputs Directory that will be used to acquire the 2FA code. This class must inherit from ibeam.src.two_fa_handlers.two_fa_handler.TwoFaHandler
and implement the method get_two_fa_code
which will be called to acquire the code.
Once you create the custom 2FA handler class, place it in the Inputs Directory and specify its fully qualified name as IBEAM_CUSTOM_TWO_FA_HANDLER
environment variable following the pattern: MODULE_NAME.CLASS_NAME. For example, for a class CustomTwoFaHandler located in a file called 'custom_two_fa_handler.py' you'd set the environment variable as custom_two_fa_handler.CustomTwoFaHandler
.
IBeam will not make any assumptions about this class or the get_two_fa_code
method, other than that it will return the 2FA code. Make sure that it doesn't block the execution of IBeam indefinitely upon failure.
Additionally, to provide more runtime logging information you can implement the __str__
method which IBeam will use to log your custom 2FA handler before execution.
The 2FA process is not using an officially supported automatic interface, therefore 2FA support is provided on basis of our best attempts to automatically perform the 2FA code acquisition and input. We provide no guarantee that the process will always complete or prevent account lock-outs due to unsuccessful attempts - although IBeam will attempt to minimise the probability of this happening.
Due to implied volatility of the 2FA authentication process, IBeam has a number of built-in security measures that should minimise issues caused by invalid authentication:
By default IBeam will parse the 2FA code returned by the handlers and accept only codes that are made of 6 digits (although both int
and str
are valid codes). You can disable this check by setting IBEAM_STRICT_TWO_FA_CODE
to False
.
As of writing this, IBKR performs a 24-hour lock-out on an account upon 10 consecutive unsuccessful login attempts. Any successful login is meant to reset this counter.
To prevent this lock-out from happening, IBeam will count the amount of consecutive failed attempts and shut down if authentication fails too many times. The environment variable IBEAM_MAX_FAILED_AUTH
defines the maximum number of failed authentication attempts that IBeam will allow. To disable this functionality, set this environment variable to a very large number.
While IBeam currently doesn't have any method of automating the 2FA out of the box, a number of suggestions were made by our users. This section lists these potential solutions:
By @jembl
https://github.com/Voyz/ibeam/issues/8#issuecomment-763353923
- I got a www.twilio.com account and got a number, changed my IB phone number to twilio phone number.
- I add a webhook for SMS, when an SMS is received, it will call my webserver i.e. www.sample.com/smshook
- use this code to parse the SMS on the server side and upload it to a storage of my choice
public String receive(String message) {
StringBuilder sb = new StringBuilder();
ResourceSet<Message> messages = Message.reader().limit(10).read();
for(Message record : messages) {
if (!smsStorageManager.getSmsWithSid(record.getSid()).isPresent()) {
String messageSid = record.getSid();
String messageBody = record.getBody();
try {
log.info("received message with SID " + record.getSid());
log.info("received message with BODY " + record.getBody());
String[] splits = messageBody.split(":");
if (messageBody.startsWith("Your requested authentication code: ")) {
String code = splits[1].trim();
twoFactorCodeBlobStorageManager.insertIntoCodeBlob(code);
}
sb.append(messageSid + "\n");
} catch (Exception e) {
log.error("Failed to process the message " + messageBody, e);
} finally {
Message.deleter(messageSid).delete();
}
}
}
return sb.toString();
}
- On the container side i read the code from storage after login inside gateway_client.py:
(Note that carrying out the following logic can now be executed using a custom TwoFaHandler, without having to modify and build the IBeam image as suggested)
sf_select_present = EC.presence_of_element_located((By.ID, _SF_SELECT_EL_ID))
WebDriverWait(driver, 15).until(sf_select_present)
_LOGGER.info("sf_select has appeared")
sf_select_el = Select(driver.find_element_by_id(_SF_SELECT_EL_ID))
sf_select_el.select_by_value('4.2')
_LOGGER.info("sf_select one time passcode")
two_factor_input_present = EC.presence_of_element_located((By.ID, _TWO_FAC_EL_ID))
WebDriverWait(driver, 15).until(two_factor_input_present)
time.sleep(45)
two_factor_el = driver.find_element_by_id(_TWO_FAC_EL_ID)
_LOGGER.info(two_factor_el.text)
two_factor_el.send_keys(get_latest_authentication_code())
_LOGGER.info('Submitting the form for two fac')
submit_form_el = driver.find_element_by_id(_SUBMIT_EL_ID)
submit_form_el.click()
success_present = EC.text_to_be_present_in_element((By.TAG_NAME, 'pre'), _SUCCESS_EL_TEXT)
WebDriverWait(driver, _OAUTH_TIMEOUT).until(success_present)
_LOGGER.info(driver.page_source.encode("utf-8"))
_LOGGER.debug('Client login succeeds')
and the code to get SMS from storage:
def get_latest_authentication_code():
connection_string = "YAYAYAYAYYA"
blob_client = BlobClient.from_connection_string(
connection_string, container_name="sms", blob_name="code.text")
# [START download_a_blob]
_LOGGER.info("downloading the code from blob")
download_stream = blob_client.download_blob()
code = download_stream.content_as_text()
_LOGGER.info("done downloading the code from blob ")
_LOGGER.info(str(code))
return code
It is unclear whether Interactive Brokers officially support disabling 2FA. In spite of that, some users were successful in disabling 2FA on their accounts. Please note that disabling 2FA comes with obvious risks, exposing your account to unwanted access. This section lists these potential methods:
By @JackD111
https://github.com/Voyz/ibeam/issues/40#issuecomment-968719424
You can create a new user linked to your main account. I believe it's restricted to only one user that runs alongside with the primary account holder. On that user you make sure to not activate 2FA because once it's enabled you can't turn it off. I'm using that second user in ibeam. This is also very nice because you can log in anytime in TWS or the client portal with your main user without taking away the session of the user logged into ibeam. My main user has 2FA enabled but the 2nd user has not 2FA enabled. Technically a security risk but it's the only way to properly run ibeam without any user interaction or google auth shananigans. What might make it secure but I haven't tried yet , is restricting the user to only be allowed to login from specific IPs which would than be my cloud machine running ibeam. That might be something worth investigating but I haven't bothered yet.
Read this article for more info about having a second user added to your account: https://ibkr.info/article/1004
Consider contributing to IBeam. Have a look at the Roadmap to get started.
See any error on this page? Create an Issue and let us know.