How do I retrieve a username with Python keyring?
Asked Answered
P

5

10

I have a Mercurial keyring on my Windows 7 machine. I am using the Python keyring library to get user credentials from the Mercurial keyring.

I can retrieve the password for a given username with:

keyring.get_password('Mercurial', 'user@@etc')

Is there a similar function to retrieve the username?

Ploughman answered 5/3, 2013 at 22:10 Comment(0)
F
7

You are expected to have stored the username somewhere else.

The keyring only stores the password, keyed by the application name and username.

Florella answered 5/3, 2013 at 22:13 Comment(0)
E
12

On Windows I was able to get both username and password (i.e. the "credentials") using

c = keyring.get_credential("servicename", None)

Note that this does not work on macOS, the keyring backend does not have capabilities to search for entries - i.e. you need to know the username. I suppose that native code would allow you to do this, though, see official docs

Evenhanded answered 8/1, 2019 at 12:25 Comment(4)
Worth mentioning that you can access the username, password like so: c.username and c.password.Beamon
This is the most accurate answer.Campanile
Worth specifying get_credential is available from Keyring 15.2.0 onwards.Brahmana
Why the official documentation does not say this?Hafnium
B
10

Update: As of Keyring 15.2.0, you can use keyring.get_credential instead.


While keyring was only designed to store passwords, you can abuse get_password to store the username separately.

import keyring

# store username & password
keyring.set_password("name_of_app", "username", "user123")
keyring.set_password("name_of_app", "password", "pass123")

# retrieve username & password
username = keyring.get_password("name_of_app", "username")
password = keyring.get_password("name_of_app", "password")

Alternatively, if you want to keep the username paired with the password:

import keyring

service_id = "name_of_app"
username = "user123"

# store username & password
keyring.set_password(service_id, "username", username)
keyring.set_password(service_id, username, "pass123")

# retrieve username & password
username = keyring.get_password(service_id, "username")
password = keyring.get_password(service_id, username)

Credit to Dustin Wyatt & Alex Chan for this solution.

Brahmana answered 16/2, 2018 at 16:39 Comment(2)
Is the key (not the password) stored securely in the keychain or does that "paired" solution expose the username?Openminded
@Openminded This depends on the backend. Pass for example stores the credentials as a path.So the username is part of that path and only the credential file is encrypted.Bringhurst
F
7

You are expected to have stored the username somewhere else.

The keyring only stores the password, keyed by the application name and username.

Florella answered 5/3, 2013 at 22:13 Comment(0)
B
3

You can retrieve a username with the get_credential function added in keyring 15.2.0.

import keyring

keyring.set_password("example_service", "example_username", "example_password")
credentials = keyring.get_credential("example_service", None)
if credentials is not None:
    username = credentials.username  # example_username
    password = credentials.password  # example_password

Credit to MShekow and Eelco van Villet for providing a similar answer

Brahmana answered 7/11, 2022 at 18:38 Comment(0)
A
2

If you want to hide your username in the script as well you can use credentials of the keyring module. Also I would recommend to use the getpass library for the input of the password; this prevents the password to be printed to screen. Finally, you may want to have a delete credentials somewhere in your code as soon as you notice that the login failed. Otherwise the script restart without the prompt to the user. As a full example. Here is how you would retrieve the username and password

import getpass
import keyring
import requests

service_name = "Name of the keyring"
credentials = keyring.get_credential(service_name, None)
if credentials is None:
    username = input("Username: ")
    password = getpass.getpass()
    keyring.set_password(service_name,username, password)
else:
    username = credentials.username
    password = credentials.password

Then you can do your thing, for instance do a post using request to an api. If it fails, delete the keyring to force to ask the credenitials again.

response = requests.post('url_to_api', auth=requests.auth.HTTPBasicAuth(username, password))
try:
    response.raise_for_status()
except requests.exceptions.HTTPError as err:
    keyring.delete_password(service_name, username)
    raise

If the login succeeds, the next time you don't have to input username and password again.

Aeolotropic answered 7/10, 2020 at 10:11 Comment(1)
This response is elegant!Spitball

© 2022 - 2024 — McMap. All rights reserved.