msalpython - MSAL Python Documentation
You can find high level conceptual documentations in the project
README and workable samples inside the project code base .
The documentation hosted here is for API Reference.
MSAL proposes a clean separation between public client
applications and confidential client applications.
They are implemented as two separated classes, with different
methods for different authentication scenarios.
- class
msal.PublicClientApplication(client_id, client_credential=None,
**kwargs)
- acquire_token_by_device_flow(flow,
claims_challenge=None, **kwargs)
- Obtain token by a device flow object, with customizable polling
effect.
- Parameters
- flow (dict) -- A dict previously generated by
initiate_device_flow(). By default, this method's polling effect
will block current thread. You can abort the polling loop at any time, by
changing the value of the flow's "expires_at" key to 0.
- claims_challenge -- The claims_challenge parameter requests
specific claims requested by the resource provider in the form of a
claims_challenge directive in the www-authenticate header to be returned
from the UserInfo Endpoint and/or in the ID Token and/or Access Token. It
is a string of a JSON object which contains lists of claims being
requested from these locations.
- Returns
- A dict representing the json response from AAD:
- A successful response would contain "access_token" key,
- an error response would contain "error" and usually
"error_description".
- acquire_token_by_username_password(username,
password, scopes, claims_challenge=None, **kwargs)
- Gets a token for a given resource via user credentials.
See this page for constraints of Username Password Flow.
https://github.com/AzureAD/microsoft-authentication-library-for-python/wiki/Username-Password-Authentication
- Parameters
- username (str) -- Typically a UPN in the form of an email
address.
- password (str) -- The password.
- scopes (list[str]) -- Scopes requested
to access a protected API (a resource).
- claims_challenge -- The claims_challenge parameter requests
specific claims requested by the resource provider in the form of a
claims_challenge directive in the www-authenticate header to be returned
from the UserInfo Endpoint and/or in the ID Token and/or Access Token. It
is a string of a JSON object which contains lists of claims being
requested from these locations.
- Returns
- A dict representing the json response from AAD:
- A successful response would contain "access_token" key,
- an error response would contain "error" and usually
"error_description".
- acquire_token_interactive(scopes,
prompt=None, login_hint=None, domain_hint=None, claims_challenge=None,
timeout=None, port=None, extra_scopes_to_consent=None,
**kwargs)
- Acquire token interactively i.e. via a local browser.
- Parameters
- scope (list) -- It is a list of case-sensitive strings.
- prompt (str) -- By default, no prompt value will be sent,
not even "none". You will have to specify a value explicitly.
Its valid values are defined in Open ID Connect specs
https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest
- login_hint (str) -- Optional. Identifier of the user.
Generally a User Principal Name (UPN).
- domain_hint --
Can be one of "consumers" or
"organizations" or your tenant domain "contoso.com".
If included, it will skip the email-based discovery process that user
goes through on the sign-in page, leading to a slightly more streamlined
user experience. More information on possible values here and
here.
- claims_challenge -- The claims_challenge parameter requests
specific claims requested by the resource provider in the form of a
claims_challenge directive in the www-authenticate header to be returned
from the UserInfo Endpoint and/or in the ID Token and/or Access Token. It
is a string of a JSON object which contains lists of claims being
requested from these locations.
- timeout (int) -- This method will block the current thread.
This parameter specifies the timeout value in seconds. Default value
None means wait indefinitely.
- port (int) -- The port to be used to listen to an incoming
auth response. By default we will use a system-allocated port. (The rest
of the redirect_uri is hard coded as http://localhost.)
- extra_scopes_to_consent (list) -- "Extra scopes to
consent" is a concept only available in AAD. It refers to other
resources you might want to prompt to consent for, in the same
interaction, but for which you won't get back a token for in this
particular operation.
- Returns
- A dict containing no "error" key, and typically contains an
"access_token" key, if cache lookup succeeded.
- A dict containing an "error" key, when token refresh
failed.
- initiate_device_flow(scopes=None,
**kwargs)
- Initiate a Device Flow instance, which will be used in
acquire_token_by_device_flow().
- Parameters
- scopes (list[str]) -- Scopes requested
to access a protected API (a resource).
- Returns
- A dict representing a newly created Device Flow object.
- A successful response would contain "user_code" key, among
others
- an error response would contain some other readable key/value pairs.
- class
msal.ConfidentialClientApplication(client_id, client_credential=None,
authority=None, validate_authority=True, token_cache=None, http_client=None,
verify=True, proxies=None, timeout=None, client_claims=None, app_name=None,
app_version=None, client_capabilities=None)
- acquire_token_for_client(scopes,
claims_challenge=None, **kwargs)
- Acquires token for the current confidential client, not for an end
user.
- Parameters
- scopes (list[str]) -- (Required) Scopes
requested to access a protected API (a resource).
- claims_challenge -- The claims_challenge parameter requests
specific claims requested by the resource provider in the form of a
claims_challenge directive in the www-authenticate header to be returned
from the UserInfo Endpoint and/or in the ID Token and/or Access Token. It
is a string of a JSON object which contains lists of claims being
requested from these locations.
- Returns
- A dict representing the json response from AAD:
- A successful response would contain "access_token" key,
- an error response would contain "error" and usually
"error_description".
- acquire_token_on_behalf_of(user_assertion,
scopes, claims_challenge=None, **kwargs)
- Acquires token using on-behalf-of (OBO) flow.
The current app is a middle-tier service which was called with
a token representing an end user. The current app can use such token
(a.k.a. a user assertion) to request another token to access downstream
web API, on behalf of that user. See detail docs here .
The current middle-tier app has no user interaction to obtain
consent. See how to gain consent upfront for your middle-tier app from
this article.
https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-on-behalf-of-flow#gaining-consent-for-the-middle-tier-application
- Parameters
- user_assertion (str) -- The incoming token already received
by this app
- scopes (list[str]) -- Scopes required
by downstream API (a resource).
- claims_challenge -- The claims_challenge parameter requests
specific claims requested by the resource provider in the form of a
claims_challenge directive in the www-authenticate header to be returned
from the UserInfo Endpoint and/or in the ID Token and/or Access Token. It
is a string of a JSON object which contains lists of claims being
requested from these locations.
- Returns
- A dict representing the json response from AAD:
- A successful response would contain "access_token" key,
- an error response would contain "error" and usually
"error_description".
Both PublicClientApplication and ConfidentialClientApplication
have following methods inherited from their base class. You typically do not
need to initiate this base class, though.
- class
msal.ClientApplication(client_id, client_credential=None, authority=None,
validate_authority=True, token_cache=None, http_client=None, verify=True,
proxies=None, timeout=None, client_claims=None, app_name=None,
app_version=None, client_capabilities=None)
- __init__(client_id, client_credential=None, authority=None,
validate_authority=True, token_cache=None, http_client=None, verify=True,
proxies=None, timeout=None, client_claims=None, app_name=None,
app_version=None, client_capabilities=None)
- Create an instance of application.
- Parameters
- client_id (str) -- Your app has a client_id after you
register it on AAD.
- client_credential (str) --
For PublicClientApplication, you simply use None
here. For ConfidentialClientApplication, it can be a string
containing client secret, or an X509 certificate container in this
form:
{
"private_key": "...-----BEGIN PRIVATE KEY-----...",
"thumbprint": "A1B2C3D4E5F6...",
"public_certificate": "...-----BEGIN CERTIFICATE-----... (Optional. See below.)",
"passphrase": "Passphrase if the private_key is encrypted (Optional. Added in version 1.6.0)",
}
Added in version 0.5.0: public_certificate (optional) is
public key certificate which will be sent through 'x5c' JWT header only for
subject name and issuer authentication to support cert auto rolls.
Per specs, "the certificate containing the public key
corresponding to the key used to digitally sign the JWS MUST be the first
certificate. This MAY be followed by additional certificates, with each
subsequent certificate being the one used to certify the previous one."
However, your certificate's issuer may use a different order. So, if your
attempt ends up with an error AADSTS700027 - "The provided signature
value did not match the expected signature value", you may try use only
the leaf cert (in PEM/str format) instead.
- •
- client_claims (dict) --
Added in version 0.5.0: It is a dictionary of extra
claims that would be signed by by this
ConfidentialClientApplication 's private key. For example, you
can use {"client_ip": "x.x.x.x"}. You may also
override any of the following default claims:
{
"aud": the_token_endpoint,
"iss": self.client_id,
"sub": same_as_issuer,
"exp": now + 10_min,
"iat": now,
"jti": a_random_uuid
}
- authority (str) -- A URL that identifies a token authority.
It should be of the format
https://login.microsoftonline.com/your_tenant By default, we will
use https://login.microsoftonline.com/common
- validate_authority (bool) -- (optional) Turns authority
validation on or off. This parameter default to true.
- cache (TokenCache) -- Sets the token cache used by this
ClientApplication instance. By default, an in-memory cache will be created
and used.
- http_client -- (optional) Your implementation of abstract class
HttpClient <msal.oauth2cli.http.http_client> Defaults to a requests
session instance
- verify -- (optional) It will be passed to the verify parameter
in the underlying requests library This does not apply if you have
chosen to pass your own Http client
- proxies -- (optional) It will be passed to the proxies parameter
in the underlying requests library This does not apply if you have
chosen to pass your own Http client
- timeout -- (optional) It will be passed to the timeout parameter
in the underlying requests library This does not apply if you have
chosen to pass your own Http client
- app_name -- (optional) You can provide your application name for
Microsoft telemetry purposes. Default value is None, means it will not be
passed to Microsoft.
- app_version -- (optional) You can provide your application version
for Microsoft telemetry purposes. Default value is None, means it will not
be passed to Microsoft.
- client_capabilities (list[str]) --
(optional) Allows configuration of one or more client
capabilities, e.g. ["CP1"].
Client capability is meant to inform the Microsoft identity
platform (STS) what this client is capable for, so STS can decide to
turn on certain features. For example, if client is capable to handle
claims challenge, STS can then issue CAE access tokens to
resources knowing when the resource emits claims challenge the
client will be capable to handle.
Implementation details: Client capability is implemented using
"claims" parameter on the wire, for now. MSAL will combine
them into
`claims parameter <https://openid.net/specs/openid-connect-core-1_0-final.html#ClaimsParameter`_
which you will later provide via one of the acquire-token
request.
- acquire_token_by_auth_code_flow(auth_code_flow,
auth_response, scopes=None, **kwargs)
- Validate the auth response being redirected back, and obtain tokens.
It automatically provides nonce protection.
- Parameters
- auth_code_flow (dict) -- The same dict returned by
initiate_auth_code_flow().
- auth_response (dict) -- A dict of the query string received
from auth server.
- scopes (list[str]) --
Scopes requested to access a protected API (a resource).
Most of the time, you can leave it empty.
If you requested user consent for multiple resources, here you
will need to provide a subset of what you required in
initiate_auth_code_flow().
OAuth2 was designed mostly for singleton services, where
tokens are always meant for the same resource and the only changes are
in the scopes. In AAD, tokens can be issued for multiple 3rd party
resources. You can ask authorization code for multiple resources, but
when you redeem it, the token is for only one intended recipient, called
audience. So the developer need to specify a scope so that we can
restrict the token to be issued for the corresponding audience.
- Returns
- A dict containing "access_token" and/or "id_token",
among others, depends on what scope was used. (See
https://tools.ietf.org/html/rfc6749#section-5.1)
- A dict containing "error", optionally
"error_description", "error_uri". (It is either
this or that)
- Most client-side data error would result in ValueError exception. So the
usage pattern could be without any protocol details:
def authorize(): # A controller in a web app
try:
result = msal_app.acquire_token_by_auth_code_flow(
session.get("flow", {}), request.args)
if "error" in result:
return render_template("error.html", result)
use(result) # Token(s) are available in result and cache
except ValueError: # Usually caused by CSRF
pass # Simply ignore them
return redirect(url_for("index"))
- acquire_token_by_authorization_code(code,
scopes, redirect_uri=None, nonce=None, claims_challenge=None,
**kwargs)
- The second half of the Authorization Code Grant.
- Parameters
- code -- The authorization code returned from Authorization
Server.
- scopes (list[str]) --
(Required) Scopes requested to access a protected API (a
resource).
If you requested user consent for multiple resources, here you
will typically want to provide a subset of what you required in
AuthCode.
OAuth2 was designed mostly for singleton services, where
tokens are always meant for the same resource and the only changes are
in the scopes. In AAD, tokens can be issued for multiple 3rd party
resources. You can ask authorization code for multiple resources, but
when you redeem it, the token is for only one intended recipient, called
audience. So the developer need to specify a scope so that we can
restrict the token to be issued for the corresponding audience.
- nonce -- If you provided a nonce when calling
get_authorization_request_url(), same nonce should also be provided
here, so that we'll validate it. An exception will be raised if the nonce
in id token mismatches.
- claims_challenge -- The claims_challenge parameter requests
specific claims requested by the resource provider in the form of a
claims_challenge directive in the www-authenticate header to be returned
from the UserInfo Endpoint and/or in the ID Token and/or Access Token. It
is a string of a JSON object which contains lists of claims being
requested from these locations.
- Returns
- A dict representing the json response from AAD:
- A successful response would contain "access_token" key,
- an error response would contain "error" and usually
"error_description".
- acquire_token_by_refresh_token(refresh_token,
scopes, **kwargs)
- Acquire token(s) based on a refresh token (RT) obtained from elsewhere.
You use this method only when you have old RTs from elsewhere,
and now you want to migrate them into MSAL. Calling this method results
in new tokens automatically storing into MSAL.
You do NOT need to use this method if you are already using
MSAL. MSAL maintains RT automatically inside its token cache, and an
access token can be retrieved when you call
acquire_token_silent().
- Parameters
- refresh_token (str) -- The old refresh token, as a
string.
- scopes (list) -- The scopes associate with this old RT. Each
scope needs to be in the Microsoft identity platform (v2) format. See
Scopes not resources.
- Returns
- A dict contains "error" and some other keys, when error
happened.
- A dict contains no "error" key means migration was
successful.
- acquire_token_silent(scopes,
account, authority=None, force_refresh=False, claims_challenge=None,
**kwargs)
- Acquire an access token for given account, without user interaction.
It is done either by finding a valid access token from cache,
or by finding a valid refresh token from cache and then automatically
use it to redeem a new access token.
This method will combine the cache empty and refresh error
into one return value, None. If your app does not care about the
exact token refresh error during token cache look-up, then this method
is easier and recommended.
Internally, this method calls
acquire_token_silent_with_error().
- Parameters
- claims_challenge -- The claims_challenge parameter requests
specific claims requested by the resource provider in the form of a
claims_challenge directive in the www-authenticate header to be returned
from the UserInfo Endpoint and/or in the ID Token and/or Access Token. It
is a string of a JSON object which contains lists of claims being
requested from these locations.
- Returns
- A dict containing no "error" key, and typically contains an
"access_token" key, if cache lookup succeeded.
- None when cache lookup does not yield a token.
- acquire_token_silent_with_error(scopes,
account, authority=None, force_refresh=False, claims_challenge=None,
**kwargs)
- Acquire an access token for given account, without user interaction.
It is done either by finding a valid access token from cache,
or by finding a valid refresh token from cache and then automatically
use it to redeem a new access token.
This method will differentiate cache empty from token refresh
error. If your app cares the exact token refresh error during token
cache look-up, then this method is suitable. Otherwise, the other method
acquire_token_silent() is recommended.
- Parameters
- scopes (list[str]) -- (Required) Scopes
requested to access a protected API (a resource).
- account -- one of the account object returned by
get_accounts(), or use None when you want to find an access token
for this client.
- force_refresh -- If True, it will skip Access Token look-up, and
try to find a Refresh Token to obtain a new Access Token.
- claims_challenge -- The claims_challenge parameter requests
specific claims requested by the resource provider in the form of a
claims_challenge directive in the www-authenticate header to be returned
from the UserInfo Endpoint and/or in the ID Token and/or Access Token. It
is a string of a JSON object which contains lists of claims being
requested from these locations.
- Returns
- A dict containing no "error" key, and typically contains an
"access_token" key, if cache lookup succeeded.
- None when there is simply no token in the cache.
- A dict containing an "error" key, when token refresh
failed.
- get_accounts(username=None)
- Get a list of accounts which previously signed in, i.e. exists in cache.
An account can later be used in acquire_token_silent()
to find its tokens.
- Parameters
- username -- Filter accounts with this username only. Case
insensitive.
- Returns
- A list of account objects. Each account is a dict. For now, we only
document its "username" field. Your app can choose to display
those information to end user, and allow user to choose one of his/her
accounts to proceed.
- get_authorization_request_url(scopes,
login_hint=None, state=None, redirect_uri=None, response_type='code',
prompt=None, nonce=None, domain_hint=None, claims_challenge=None,
**kwargs)
- Constructs a URL for you to start a Authorization Code Grant.
- Parameters
- scopes (list[str]) -- (Required) Scopes
requested to access a protected API (a resource).
- state (str) -- Recommended by OAuth2 for CSRF
protection.
- login_hint (str) -- Identifier of the user. Generally a User
Principal Name (UPN).
- redirect_uri (str) -- Address to return to upon receiving a
response from the authority.
- response_type (str) --
Default value is "code" for an OAuth2 Authorization
Code grant.
You could use other content such as "id_token" or
"token", which would trigger an Implicit Grant, but that is
not recommended.
- prompt (str) -- By default, no prompt value will be sent,
not even "none". You will have to specify a value explicitly.
Its valid values are defined in Open ID Connect specs
https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest
- nonce -- A cryptographically random value used to mitigate replay
attacks. See also OIDC specs.
- domain_hint --
Can be one of "consumers" or
"organizations" or your tenant domain "contoso.com".
If included, it will skip the email-based discovery process that user
goes through on the sign-in page, leading to a slightly more streamlined
user experience. More information on possible values here and
here.
- claims_challenge -- The claims_challenge parameter requests
specific claims requested by the resource provider in the form of a
claims_challenge directive in the www-authenticate header to be returned
from the UserInfo Endpoint and/or in the ID Token and/or Access Token. It
is a string of a JSON object which contains lists of claims being
requested from these locations.
- Returns
- The authorization url as a string.
- initiate_auth_code_flow(scopes,
redirect_uri=None, state=None, prompt=None, login_hint=None,
domain_hint=None, claims_challenge=None)
- Initiate an auth code flow.
Later when the response reaches your redirect_uri, you can use
acquire_token_by_auth_code_flow() to complete the
authentication/authorization.
- Parameters
- scope (list) -- It is a list of case-sensitive strings.
- redirect_uri (str) -- Optional. If not specified, server
will use the pre-registered one.
- state (str) -- An opaque value used by the client to
maintain state between the request and callback. If absent, this library
will automatically generate one internally.
- prompt (str) -- By default, no prompt value will be sent,
not even "none". You will have to specify a value explicitly.
Its valid values are defined in Open ID Connect specs
https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest
- login_hint (str) -- Optional. Identifier of the user.
Generally a User Principal Name (UPN).
- domain_hint --
Can be one of "consumers" or
"organizations" or your tenant domain "contoso.com".
If included, it will skip the email-based discovery process that user
goes through on the sign-in page, leading to a slightly more streamlined
user experience. More information on possible values here and
here.
- Returns
- The auth code flow. It is a dict in this form:
{
"auth_uri": "https://...", // Guide user to visit this
"state": "...", // You may choose to verify it by yourself,
// or just let acquire_token_by_auth_code_flow()
// do that for you.
"...": "...", // Everything else are reserved and internal
}
The caller is expected to:
- 1.
- somehow store this content, typically inside the current session,
- 2.
- guide the end user (i.e. resource owner) to visit that auth_uri,
- 3.
- and then relay this dict and subsequent auth response to
acquire_token_by_auth_code_flow().
One of the parameter accepted by both
PublicClientApplication and ConfidentialClientApplication is
the TokenCache.
- class
msal.TokenCache
- This is considered as a base class containing minimal cache behavior.
Although it maintains tokens using unified schema across all
MSAL libraries, this class does not serialize/persist them. See subclass
SerializableTokenCache for details on serialization.
- add()
- Handle a token obtaining event, and add tokens into cache.
Known side effects: This function modifies the input event in
place.
You can subclass it to add new behavior, such as, token
serialization. See SerializableTokenCache for example.
- class
msal.SerializableTokenCache
- This serialization can be a starting point to implement your own
persistence.
This class does NOT actually persist the cache on
disk/db/etc.. Depending on your need, the following simple recipe for
file-based persistence may be sufficient:
import os, atexit, msal
cache = msal.SerializableTokenCache()
if os.path.exists("my_cache.bin"):
cache.deserialize(open("my_cache.bin", "r").read())
atexit.register(lambda:
open("my_cache.bin", "w").write(cache.serialize())
# Hint: The following optional line persists only when state changed
if cache.has_state_changed else None
)
app = msal.ClientApplication(..., token_cache=cache)
...
- Variables
- has_state_changed (bool) -- Indicates whether the cache
state in the memory has changed since last serialize() or
deserialize() call.
- add(event,
**kwargs)
- Handle a token obtaining event, and add tokens into cache.
Known side effects: This function modifies the input event in
place.