OAuthlib support for Python-Requests!

Overview

Requests-OAuthlib build-status coverage-status Documentation Status

This project provides first-class OAuth library support for Requests.

The OAuth 1 workflow

OAuth 1 can seem overly complicated and it sure has its quirks. Luckily, requests_oauthlib hides most of these and let you focus at the task at hand.

Accessing protected resources using requests_oauthlib is as simple as:

>>> from requests_oauthlib import OAuth1Session
>>> twitter = OAuth1Session('client_key',
                            client_secret='client_secret',
                            resource_owner_key='resource_owner_key',
                            resource_owner_secret='resource_owner_secret')
>>> url = 'https://api.twitter.com/1/account/settings.json'
>>> r = twitter.get(url)

Before accessing resources you will need to obtain a few credentials from your provider (e.g. Twitter) and authorization from the user for whom you wish to retrieve resources for. You can read all about this in the full OAuth 1 workflow guide on RTD.

The OAuth 2 workflow

OAuth 2 is generally simpler than OAuth 1 but comes in more flavours. The most common being the Authorization Code Grant, also known as the WebApplication flow.

Fetching a protected resource after obtaining an access token can be extremely simple. However, before accessing resources you will need to obtain a few credentials from your provider (e.g. Google) and authorization from the user for whom you wish to retrieve resources for. You can read all about this in the full OAuth 2 workflow guide on RTD.

Installation

To install requests and requests_oauthlib you can use pip:

$ pip install requests requests_oauthlib
Comments
  • The URL should always be native.

    The URL should always be native.

    This should resolve the issue that @michaelhelmick had in kennethreitz/requests#1366. In short, the keys for doing Transport Adapter lookups are native strings, but requests_oauthlib turns the URL into bytes. Not helpful. This prevents that behaviour while avoiding regressing kennethreitz/requests#1252.

    opened by Lukasa 50
  • Refresh Tokens + Web App Example?

    Refresh Tokens + Web App Example?

    I've been trying to wrap my head around refresh tokens and the OAuth2 web example (https://requests-oauthlib.readthedocs.org/en/latest/examples/real_world_example.html). Would it be possible to provide an example usage of refresh tokens in that context? Where in the code it would go, etc?

    Just a suggestion! :grin:

    docs 
    opened by bryanveloso 24
  • Fix dependencies

    Fix dependencies

    Each time the oauthlib library is changed, I have to change my code because the behaviour changes. So, can you fix the version of the libraries that you use? At least you should fix the mayor number of the dependencies since when this number changes, the API often changes.

    opened by aitormagan 23
  • AttributeError: 'PreparedRequest' object has no attribute 'data'

    AttributeError: 'PreparedRequest' object has no attribute 'data'

    @Lukasa asked me to raise this error in this repo as well:

    Hey guys, just wanted to bring this issue forward. With requests 1.0.0 So the error came from when I went to test Twython with the new requests release.

    And because it bothered me, I removed self from all variables that used self like self.callback_url Also, I striped the code out of the actual function get_authentication_tokens (so that's why you'll see ref to that function in the traceback)

    import requests
    from requests_oauthlib import OAuth1
    
    app_key = u'SUPERDUPERSECRETKEY'
    app_secret = u'SUPERDUPERSECRETSECRET'
    
    callback_url = 'http://example.com'
    headers = {'User-Agent': 'Twython v2.5.5'}
    auth = OAuth1(app_key, app_secret,
                                   signature_type='auth_header')
    
    request_args['oauth_callback'] = callback_url
    response = requests.get('https://api.twitter.com/oauth/request_token', params=request_args, headers=headers, auth=auth)
    
    if response.status_code != 200:
        raise TwythonAuthError("Seems something couldn't be verified with your OAuth junk. Error: %s, Message: %s" % (response.status_code, response.content))
    
    request_tokens = dict(parse_qsl(response.content))
    if not request_tokens:
        raise TwythonError('Unable to decode request tokens.')
    
    oauth_callback_confirmed = request_tokens.get('oauth_callback_confirmed') == 'true'
    
    auth_url_params = {
        'oauth_token': request_tokens['oauth_token'],
    }
    
    # Use old-style callback argument if server didn't accept new-style
    if callback_url and not oauth_callback_confirmed:
        auth_url_params['oauth_callback'] = callback_url
    
    request_tokens['auth_url'] = 'https://api.twitter.com/oauth/authenticate?' + urllib.urlencode(auth_url_params)
    
    return request_tokens
    

    Anyways, when I try to run this code I get the error:

    Traceback (most recent call last):
      File "twython.py", line 585, in <module>
        auth_props = t.get_authentication_tokens()
      File "twython.py", line 271, in get_authentication_tokens
        response = requests.get('https://api.twitter.com/oauth/request_token', params=request_args, headers=headers, auth=self.auth)
      File "/Users/mikehelmick/.virtualenv/twython/lib/python2.7/site-packages/requests/api.py", line 49, in get
        return request('get', url, **kwargs)
      File "/Users/mikehelmick/.virtualenv/twython/lib/python2.7/site-packages/requests/api.py", line 38, in request
        return session.request(method=method, url=url, **kwargs)
      File "/Users/mikehelmick/.virtualenv/twython/lib/python2.7/site-packages/requests/sessions.py", line 253, in request
        prep = req.prepare()
      File "/Users/mikehelmick/.virtualenv/twython/lib/python2.7/site-packages/requests/models.py", line 200, in prepare
        p.prepare_auth(self.auth)
      File "/Users/mikehelmick/.virtualenv/twython/lib/python2.7/site-packages/requests/models.py", line 336, in prepare_auth
        r = auth(self)
      File "/Users/mikehelmick/.virtualenv/twython/lib/python2.7/site-packages/requests_oauthlib/core.py", line 41, in __call__
        decoded_body = extract_params(r.data)
    AttributeError: 'PreparedRequest' object has no attribute 'data'
    
    opened by michaelhelmick 20
  • Sort out the documentation

    Sort out the documentation

    We've finally got some stuff up on ReadTheDocs, but it's not great. This issue is an umbrella tracking issue, so I can tick stuff off as we go. Here are some things we need to do: feel free to suggest more in the comments.

    • [ ] Sort out the README (partly in #46).
    • [x] Sort out Intersphinx (see #47).
    • [ ] Remove lengthy worked examples from the API docs.
    • [ ] Put lengthy worked examples somewhere else (see #46).
    • [ ] Improve clarity of API docs.
    • [ ] Improve landing page.
    • [ ] Tutorials. Lots of tutorials. A whole tutorials section (see #49).
    enhancement Contributor Friendly docs 
    opened by Lukasa 19
  • Forcing HTTPBasicAuth in fetch_token results in invalid_request from Google

    Forcing HTTPBasicAuth in fetch_token results in invalid_request from Google

    Using Flask_OAuth2_Login (for example):

      def login(self):
        sess = self.session()
    
        # Get token
        try:
          sess.fetch_token(
            self.token_url,
            code=request.args["code"],
            client_secret=self.client_secret,
          )
    

    results in:

      File "/lib/python2.7/site-packages/flask_oauth2_login/base.py", line 56, in login
        client_secret=self.client_secret,
      File "/lib/python2.7/site-packages/requests_oauthlib/oauth2_session.py", line 232, in fetch_token
        self._client.parse_request_body_response(r.text, scope=self.scope)
      File "/lib/python2.7/site-packages/oauthlib/oauth2/rfc6749/clients/base.py", line 409, in parse_request_body_response
        self.token = parse_token_response(body, scope=scope)
      File "/lib/python2.7/site-packages/oauthlib/oauth2/rfc6749/parameters.py", line 376, in parse_token_response
        validate_token_parameters(params)
      File "/lib/python2.7/site-packages/oauthlib/oauth2/rfc6749/parameters.py", line 383, in validate_token_parameters
        raise_from_error(params.get('error'), params)
      File "/lib/python2.7/site-packages/oauthlib/oauth2/rfc6749/errors.py", line 271, in raise_from_error
        raise cls(**kwargs)
    

    This is due to a change introduced in 0.6.0 in oauth2_session.py/fetch_token:

    auth = auth or requests.auth.HTTPBasicAuth(username, password)
    

    whereas previously auth was allowed to remain empty. Google responds with:

    {
      "error" : "invalid_request"
    }
    

    and everything falls down from there. Commenting out the line allows the request to complete normally.

    opened by butlertron 17
  • Only pass bytes to urllib3.

    Only pass bytes to urllib3.

    This should resolve requests-oauthlib's problems with uploading binary data, as demonstrated in kennethreitz/requests#1252.

    @sigmavirus24, can I get code review on this before I merge into master?

    opened by Lukasa 17
  • OAuth2Session(client_id=client_id, client=client) return 403 error in production environment

    OAuth2Session(client_id=client_id, client=client) return 403 error in production environment

    OAuth2Session(client_id=client_id, client=client) return 403 error in production environment. Works good in localhost

    In localhost and production environment I disabled OAUTHLIB_INSECURE_TRANSPORT os.environ['OAUTHLIB_INSECURE_TRANSPORT'] = '1'

    opened by ilGuccio 14
  • Fix spaces encoding in parameters

    Fix spaces encoding in parameters

    OAuth requires spaces to be encoded as %20 instead of + in order to generate a valid signature.

    Explained in http://troy.yort.com/2-common-problems-with-oauth-client-libraries/

    Before this patch, I was unable to use Yahoo!'s BOSS Placefinder API, which now seems to be responding correctly to me, instead of what it used to say:

    <?xml version='1.0' encoding='UTF-8'?>
    <yahoo:error xmlns:yahoo='http://yahooapis.com/v1/base.rng'
      xml:lang='en-US'>
      <yahoo:description>Please provide valid credentials. OAuth oauth_problem="signature_invalid", realm="yahooapis.com"</yahoo:description>
    </yahoo:error>
    
    opened by Xowap 14
  • Tidying up a bit for requests 1.0

    Tidying up a bit for requests 1.0

    I've added some initial tests and cleaned up the extension code a bit.

    Unfortunately this code depends heavily on an update to requests.models.py in which lines 200 & 201 are swapped, i.e.

        p.prepare_auth(self.auth)
        p.prepare_body(self.data, self.files)
    

    becomes

        p.prepare_body(self.data, self.files)
        p.prepare_auth(self.auth)
    

    Why? Because we have no idea in auth whether body will soon be filled with files data or not and consequently it would be foolish to assume form encoded on empty body.

    I've not had time to look into what implications this might have for requests. Will send a PR when I have. @kennethreitz

    opened by ib-lundgren 14
  • Prepare 0.4.0 release

    Prepare 0.4.0 release

    The current 0.3.0 release is pretty old and we've fixed a few bugs, as well as added a massive amount of functionality. I want to get this library into a shape where we can pass it to Kenneth all he has to do is tag it and go. @ib-lundgren, @sigmavirus24, is there anything we need to do?

    opened by Lukasa 13
  • Scope changes with Microsoft services & `offline_access`

    Scope changes with Microsoft services & `offline_access`

    I'm trying to set up OAuth2 for unattended access to Microsoft IMAP servers - the refresh_token is important here.

    When providing a request scope set as follows:

    • offline_access
    • https://outlook.office.com/User.Read
    • https://outlook.office.com/IMAP.AccessAsUser.All

    The service responds with the following (i.e: offline_access is removed):

    • https://outlook.office.com/User.Read
    • https://outlook.office.com/IMAP.AccessAsUser.All

    This results in a warning being raised.

    Traceback
    Traceback (most recent call last):
      File "./oauth2-test.py", line 51, in <module>
        token = oauth.fetch_token(token_url, client_secret=client_secret, authorization_response=redirect_response)
      File "/usr/lib/python3.8/site-packages/requests_oauthlib/oauth2_session.py", line 366, in fetch_token
        self._client.parse_request_body_response(r.text, scope=self.scope)
      File "/usr/lib/python3.8/site-packages/oauthlib/oauth2/rfc6749/clients/base.py", line 427, in parse_request_body_response
        self.token = parse_token_response(body, scope=scope)
      File "/usr/lib/python3.8/site-packages/oauthlib/oauth2/rfc6749/parameters.py", line 441, in parse_token_response
        validate_token_parameters(params)
      File "/usr/lib/python3.8/site-packages/oauthlib/oauth2/rfc6749/parameters.py", line 471, in validate_token_parameters
        raise w
    Warning: Scope has changed from "https://outlook.office.com/User.Read https://outlook.office.com/IMAP.AccessAsUser.All offline_access" to "https://outlook.office.com/User.Read https://outlook.office.com/IMAP.AccessAsUser.All".
    

    Apparently the offline_access scope should never be returned by Microsoft services, as it's not actually a useful scope for accessing resources (ref).


    My current approach (which isn't ideal), is as follows:

    oauth = OAuth2Session(client_id, redirect_uri=redirect_uri, scope=scope)
    authorization_url, state = oauth.authorization_url(authorize_url)
    
    # remove the `offline_access` scope directly / by hand
    oauth.scope.remove('offline_access')
    
    # ... submit the request to authorization_url, and retrieve the token
    redirect_response = ...
    token = oauth.fetch_token(token_url, client_secret=client_secret, authorization_response=redirect_response)
    

    I'm aware of OAUTHLIB_RELAX_TOKEN_SCOPE (link), but that seems perhaps a little over-permissive.

    Perhaps one of the following would be a good idea?

    • A more generic mechanism to permit accepting scope changes
    • A way to supply the expected response set of scopes
    • A list of "I don't mind if these aren't grated" scopes
    opened by attie-argentum 0
  • Requirements out of date

    Requirements out of date

    The version of requests pinned by this library is 2.26.0.

    requests==2.26.0

    Currently, requests is at version 2.28.1. Please consider updating the requirements or leaving the requests version unpinned, as it is in requirements.in.

    Thanks!

    opened by MooseV2 1
  • Add refresh token exception hook to list of compliance hooks?

    Add refresh token exception hook to list of compliance hooks?

    I have a use case were sometimes my stored users' tokens expire and thus they need to reauthenticate into whatever app I'm trying to request data from.

    In these cases I get an error 400 from the api I'm requesting from and simply ask my user to reauthenticate using my usual oAuth2 flow.

    Since I don't know exactly when a token will expire my current approach is to wrap every request I make to these apis in a try catch and then handle the exception from there.

    I noticed that there are some compliance hooks and was wondering if it would be appropriate to add something like a refresh_token_exception hook to be called if the library runs into an error code while refreshing the token as opposed to just calling the usual refresh_token_response with the raw response.

    If this makes sense I would be happy to submit a pull request for it

    https://github.com/requests/requests-oauthlib/blob/3a2a852e33c691c7e793300ce366a01b6e4b3848/requests_oauthlib/oauth2_session.py#L94

    opened by ramennoodles20 0
  • `oauth2_session.OAuth2Session.refresh_token` creates infinite loop with Exchange Online when token expires

    `oauth2_session.OAuth2Session.refresh_token` creates infinite loop with Exchange Online when token expires

    Using an expired access token with Microsoft Exchange Online for sending Outlook e-mails under exchangelib runs into an infinite loop during the token refresh just because the app creds are bundled into the body structure instead of being provided as a (client_id, client_secret) pair given the auth object. (context)

    Is it possible to automatically create and use an auth object (if it isn't provided explicitly by the caller) based on these refresh kwargs (if they contain the client creds) right inside of oauth2_session.OAuth2Session.refresh_token so the /token POST will benefit from this implicit auth object and make the server auth working with Exchange?

    opened by cmin764 0
  • WIP: Add PKCE support with oauthlib 3.2.0

    WIP: Add PKCE support with oauthlib 3.2.0

    Since oauthlib 3.2.0 now supports PKCE for Clients (https://github.com/oauthlib/oauthlib/releases/tag/v3.2.0), this PR proposes a first implementation . Any feedbacks are welcome, I'm not sure it is production ready yet.

    Change from: session = OAuth2Session(client_id) to session = OAuth2Session(app.client_id, pkce="S256")

    And be sure to reuse the same session for fetch_token, as it will need to remember code_verifier. It is not really practical beyond PoC, so any suggestions are welcome.

    opened by JonathanHuot 0
Releases(v1.3.1)
  • v1.3.1(Jan 29, 2022)

    What's Changed

    • Add Support for OAuth Mutual TLS (draft-ietf-oauth-mtls) by @danielfett in https://github.com/requests/requests-oauthlib/pull/389
    • Linkedin compliance removal & LinkedIn Example update/fix by @jtroussard in https://github.com/requests/requests-oauthlib/pull/397
    • docs: Fix typos in token refresh section of oauth2 worflow by @momobel in https://github.com/requests/requests-oauthlib/pull/413
    • Add eBay compliance fix by @craiga in https://github.com/requests/requests-oauthlib/pull/456
    • Fix Docs generation - Improve Pipeline by @JonathanHuot in https://github.com/requests/requests-oauthlib/pull/459
    • Fix Sphinx error for oauth1 fetch_token documentation by @JonathanHuot in https://github.com/requests/requests-oauthlib/pull/462
    • Move from Travis to GitHub Actions by @JonathanHuot in https://github.com/requests/requests-oauthlib/pull/470
    • Add Spotify OAuth 2 Tutorial by @odysseusmax in https://github.com/requests/requests-oauthlib/pull/471
    • Update documentation for Python 3 by @gschizas in https://github.com/requests/requests-oauthlib/pull/435
    • docs: add the link to the Application Registration Portal by @Abdelkrim in https://github.com/requests/requests-oauthlib/pull/425
    • docs: rearrange and link spotify tutorial by @odysseusmax in https://github.com/requests/requests-oauthlib/pull/472
    • Update google.rst by @mrwangjianhui in https://github.com/requests/requests-oauthlib/pull/454
    • Add Python 3.8 & 3.9 as supported versions by @kaxil in https://github.com/requests/requests-oauthlib/pull/442
    • Update build badge for GitHub Actions by @hugovk in https://github.com/requests/requests-oauthlib/pull/475

    New Contributors

    • @danielfett made their first contribution in https://github.com/requests/requests-oauthlib/pull/389
    • @jtroussard made their first contribution in https://github.com/requests/requests-oauthlib/pull/397
    • @momobel made their first contribution in https://github.com/requests/requests-oauthlib/pull/413
    • @craiga made their first contribution in https://github.com/requests/requests-oauthlib/pull/456
    • @JonathanHuot made their first contribution in https://github.com/requests/requests-oauthlib/pull/459
    • @odysseusmax made their first contribution in https://github.com/requests/requests-oauthlib/pull/471
    • @gschizas made their first contribution in https://github.com/requests/requests-oauthlib/pull/435
    • @Abdelkrim made their first contribution in https://github.com/requests/requests-oauthlib/pull/425
    • @mrwangjianhui made their first contribution in https://github.com/requests/requests-oauthlib/pull/454
    • @kaxil made their first contribution in https://github.com/requests/requests-oauthlib/pull/442
    • @hugovk made their first contribution in https://github.com/requests/requests-oauthlib/pull/475

    Full Changelog: https://github.com/requests/requests-oauthlib/compare/v1.3.0...v1.3.1

    Source code(tar.gz)
    Source code(zip)
  • v1.3.0(Nov 2, 2021)

  • v1.2.0(Nov 2, 2021)

    • This project now depends on OAuthlib 3.0.0 and above. It does not support versions of OAuthlib before 3.0.0.
    • Updated oauth2 tests to use 'sess' for an OAuth2Session instance instead of auth because OAuth2Session objects and methods acceept an auth paramether which is typically an instance of requests.auth.HTTPBasicAuth
    • OAuth2Session.fetch_token previously tried to guess how and where to provide "client" and "user" credentials incorrectly. This was incompatible with some OAuth servers and incompatible with breaking changes in oauthlib that seek to correctly provide the client_id. The older implementation also did not raise the correct exceptions when username and password are not present on Legacy clients.
    • Avoid automatic netrc authentication for OAuth2Session.
    Source code(tar.gz)
    Source code(zip)
  • v1.1.0(Jan 9, 2019)

    • Adjusted version specifier for oauthlib dependency: this project is not yet compatible with oauthlib 3.0.0.
    • Dropped dependency on nose.
    • Minor changes to clean up the code and make it more readable/maintainable.
    Source code(tar.gz)
    Source code(zip)
  • v1.0.0(Jun 4, 2018)

    • Removed support for Python 2.6 and Python 3.3. This project now supports Python 2.7, and Python 3.4 and above.
    • Added several examples to the documentation.
    • Added plentymarkets compliance fix.
    • Added a token property to OAuth1Session, to match the corresponding token property on OAuth2Session.
    Source code(tar.gz)
    Source code(zip)
Doing the OAuth dance with style using Flask, requests, and oauthlib.

Flask-Dance Doing the OAuth dance with style using Flask, requests, and oauthlib. Currently, only OAuth consumers are supported, but this project coul

David Baumgold 799 Feb 17, 2021
Doing the OAuth dance with style using Flask, requests, and oauthlib.

Flask-Dance Doing the OAuth dance with style using Flask, requests, and oauthlib. Currently, only OAuth consumers are supported, but this project coul

David Baumgold 802 Feb 22, 2021
Foundation Auth Proxy is an abstraction on Foundations' authentication layer and is used to authenticate requests to Atlas's REST API.

foundations-auth-proxy Setup By default the server runs on http://0.0.0.0:5558. This can be changed via the arguments. Arguments: '-H' or '--host': ho

Dessa - Open Source 2 Jul 3, 2020
Django CAS 1.0/2.0/3.0 client authentication library, support Django 2.0, 2.1, 2.2, 3.0 and Python 3.5+

django-cas-ng django-cas-ng is Django CAS (Central Authentication Service) 1.0/2.0/3.0 client library to support SSO (Single Sign On) and Single Logou

django-cas-ng 347 Dec 18, 2022
python-social-auth and oauth2 support for django-rest-framework

Django REST Framework Social OAuth2 This module provides OAuth2 social authentication support for applications in Django REST Framework. The aim of th

null 1k Dec 22, 2022
python-social-auth and oauth2 support for django-rest-framework

Django REST Framework Social OAuth2 This module provides OAuth2 social authentication support for applications in Django REST Framework. The aim of th

null 1k Dec 22, 2022
An open source Flask extension that provides JWT support (with batteries included)!

Flask-JWT-Extended Features Flask-JWT-Extended not only adds support for using JSON Web Tokens (JWT) to Flask for protecting views, but also many help

Landon Gilbert-Bland 1.4k Jan 4, 2023
FastAPI extension that provides JWT Auth support (secure, easy to use, and lightweight)

FastAPI JWT Auth Documentation: https://indominusbyte.github.io/fastapi-jwt-auth Source Code: https://github.com/IndominusByte/fastapi-jwt-auth Featur

Nyoman Pradipta Dewantara 468 Jan 1, 2023
JSON Web Token Authentication support for Django REST Framework

REST framework JWT Auth Notice This project is currently unmaintained. Check #484 for more details and suggested alternatives. JSON Web Token Authenti

José Padilla 3.2k Dec 31, 2022
JSON Web Token Authentication support for Django REST Framework

REST framework JWT Auth JSON Web Token Authentication support for Django REST Framework Overview This package provides JSON Web Token Authentication s

Styria Digital Development 178 Jan 2, 2023
An enhanced permission system which support object permission in Django

django-permission Author Alisue <[email protected]> Supported python versions Python 2.7, 3.3, 3.4, 3.5, 3.6 Supported django versions Django 1

Alisue 299 Dec 6, 2022
Easy and secure implementation of Azure AD for your FastAPI APIs 🔒 Single- and multi-tenant support.

Easy and secure implementation of Azure AD for your FastAPI APIs ?? Single- and multi-tenant support.

Intility 220 Jan 5, 2023
Login-python - Login system made in Python, using native libraries

login-python Sistema de login feito 100% em Python, utilizando bibliotecas nativ

Nicholas Gabriel De Matos Leal 2 Jan 28, 2022
The ultimate Python library in building OAuth, OpenID Connect clients and servers. JWS,JWE,JWK,JWA,JWT included.

Authlib The ultimate Python library in building OAuth and OpenID Connect servers. JWS, JWK, JWA, JWT are included. Authlib is compatible with Python2.

Hsiaoming Yang 3.4k Jan 4, 2023
JSON Web Token implementation in Python

PyJWT A Python implementation of RFC 7519. Original implementation was written by @progrium. Sponsor If you want to quickly add secure token-based aut

José Padilla 4.5k Jan 9, 2023
A JOSE implementation in Python

python-jose A JOSE implementation in Python Docs are available on ReadTheDocs. The JavaScript Object Signing and Encryption (JOSE) technologies - JSON

Michael Davis 1.2k Dec 28, 2022
Python module for generating and verifying JSON Web Tokens

python-jwt Module for generating and verifying JSON Web Tokens. Note: From version 2.0.1 the namespace has changed from jwt to python_jwt, in order to

David Halls 210 Dec 24, 2022
Google Auth Python Library

Google Auth Python Library This library simplifies using Google's various server-to-server authentication mechanisms to access Google APIs. Installing

Google APIs 598 Jan 7, 2023
Python One-Time Password Library

PyOTP - The Python One-Time Password Library PyOTP is a Python library for generating and verifying one-time passwords. It can be used to implement tw

PyAuth 2.2k Dec 26, 2022