Source code for simple_openid_connect.flows.direct_access_grant

"""
The *Direct Access Grant* (or *Resource Owner Password Credentials Grant*).

Using this flow, a users credentials (i.e. username and password) are directly sent to the OpenId issuer.

.. warning::
    This way of exchanging credentials for tokens is considered legacy and not recommended but some app designs may still require it.
    The latest `OAuth 2.0 Security Best Current Practices <https://oauth.net/2/oauth-best-practice/>`_ even disallows the password grant entirely.
"""

import logging
from typing import Union

import requests

from simple_openid_connect.client_authentication import ClientAuthenticationMethod
from simple_openid_connect.data import (
    TokenErrorResponse,
    TokenRequest,
    TokenSuccessResponse,
)

logger = logging.getLogger(__name__)


[docs] def authenticate( token_endpoint: str, scope: str, username: str, password: str, client_authentication: ClientAuthenticationMethod, ) -> Union[TokenSuccessResponse, TokenErrorResponse]: """ Exchange a given username and password for access, refresh and id tokens. :param token_endpoint: The endpoint of the OP at which tokens can be exchanged. Corresponds to :data:`ProviderMetadata.token_endpoint <simple_openid_connect.data.ProviderMetadata.token_endpoint>`. :param scope: The scope requested by the application :param username: Username of the user who should be authenticated. :param password: Password of the user who should be authenticated. :param client_authentication: A way for the client to authenticate itself :returns: The result of the exchange """ logger.debug("exchanging username/password for tokens") request_msg = TokenRequest( grant_type="password", scope=scope, username=username, password=password, ) response = requests.post( token_endpoint, data=request_msg.encode_x_www_form_urlencoded(), headers={"Content-Type": "application/x-www-form-urlencoded"}, auth=client_authentication, ) if response.status_code == 200: return TokenSuccessResponse.model_validate_json(response.content) else: return TokenErrorResponse.model_validate_json(response.content)