Substra / substra

Low-level Python library used to interact with a Substra network

Home Page:https://docs.substra.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

[Feature request] Save the authentication token when logging from the SDK

Esadruhn opened this issue · comments

Current behaviour

When the user logs in from the CLI, the token is saved so he can create a client from the SDK (with the same configuration) and use the API without logging again.

When the user logs in from the SDK, the token is not saved so he has to log again if he uses the CLI. It also means that if the user is logged in the CLI and logs in the SDK, a new token is generated and he is no longer logged in the CLI.

Feature

Automatically save the authentication token when logging from the SDK.
It is possible only if the user logs from a config file (there is no profile name otherwise, nor config_path, token_path)

Caveat

This means that if the user logs from a config file, the token is saved, but if he creates the client (__init__ function) then uses the login function to log in, it does not work.
A workaround would be to create a save_token function (and/or save_profile) which asks for a profile name and config_paths/token_paths and saves the token / the profile.

commented

Hi, this would really ease end users workflow using both SDK & CLI without re-login/new token!

If there is no profile name, and no config file, we could update the default profile and the default config file?

I'm not in favour of adding new methods to manually handle token and profile, I think it's better if it's handled under the hood and the user does not have to deal with this.

If there is no profile name, and no config file, we could update the default profile and the default config file?

This could erase valid tokens. I'd say that we only save the token if the client was instantiated via "from_config_file". Because if not, we do not know with certainty where to save the token and for which profile.

Thank you for your feedback !

Actually I realise either the code has changed or I read it badly (probably the case, sorry 😔 ), the behaviour is not exactly what I wrote.

For now the user can connect in two ways with the SDK:

  1. Using the __init__ and login functions
client = Client(url= ..., .., token=...)
# If we do not give a valid token as input, need to login
client.login(username=..., password=...) 
  1. Using the from_config_file and login functions:
client = Client.from_config_file(profile_name= ..., tokens_path=...., token=....)
# If we do not give a valid token as input, 
# or there is no token in the 'token file' for this profile, need to login
client.login(username=..., password=...) 

In both methods, since we do not save the profile name, we do not know which profile the token goes with, with the
afore mentioned problems of default value and overwriting.

So either we

  • save the profile name and token file path in the client when using 'from_config_file'
  • use these values to save the token in the 'login' method
    and
  • ask the user for a profile name, and token file path in the init method too
  • use these values to save the token in the 'login' method

or

  • use extra methods to save the token, like 'save_token', but as @samlesu said, if the user does not change the config file himself then all of this should be under the hood.

I think that risking to overwrite a token is not too big a risk since by definition it is a temporary value. Implementing the first proposition (save the profile name and token file path) seems OK to me but I may be overlooking some cases.

The change in function signature would be:

def __init__(
        self,
        url: typing.Optional[str] = None,
        token: typing.Optional[str] = None,
        profile_name: typing.Optional[str] = cfg.DEFAULT_PROFILE_NAME,  # NEW
        tokens_path: typing.Union[str, pathlib.Path] = cfg.DEFAULT_TOKENS_PATH,  # NEW
        retry_timeout: int = DEFAULT_RETRY_TIMEOUT,
        version: str = '0.0',
        insecure: bool = False,
        debug: bool = False,
    ):
    # if not token and (profile_name and tokens_path): get token from file
    pass

def from_config_file(
        cls,
        profile_name: str = cfg.DEFAULT_PROFILE_NAME,
        config_path: typing.Union[str, pathlib.Path] = cfg.DEFAULT_PATH,
        tokens_path: typing.Union[str, pathlib.Path] = cfg.DEFAULT_TOKENS_PATH,
        token: typing.Optional[str] = None,
        retry_timeout: int = DEFAULT_RETRY_TIMEOUT,
        debug: bool = False
    ):
    # 'from_config_file' means taking the url, version, insecure from the config file 
    # but the token is taken from the token file in the __init__ too
    pass

In this case, could we get rid of the from_config_file method?

It would add only one extra arg to the __init__. It will imply some small changes in the constructor to override the config options with the optional input values.

Stale issue