Having trouble getting MSAL Authorization Code workflow to work - python

I am building a desktop python application that uses the MSAL authorization code workflow by opening up a browser window for authentication. I keep getting back an invalid grant error (code 70000) for some accounts but not others when trying to get an authorization token. It seems to work just fine for the personal Microsoft account through which the application is registered in the Azure portal. It also works fine for my university account (a school Microsoft account), but not for other personal Microsoft accounts.
Through the Azure portal, the application is registered with the ability for all Microsoft accounts to work with it. The scopes listed there also match the scopes that I am requesting in the python application.
The authorize endpoint does return a valid looking authorization code, but then when I try to use that code to get a valid token, I get the error. More specifically, the message associated with the error says:
AADSTS70000: The request was denied because one or more scopes requested are unauthorized or expired. The user must first sign in and grant the client application access to the requested scope.\r\nTrace ID: 6afddbd2-308e-44df-8640-976dc1c1f601\r\nCorrelation ID: bdb626d0-0a3d-4333-ac8f-b5ff510ca046\r\nTimestamp: 2022-07-24 18:50:23Z
What might be causing this issue to occur?

It turns out this was an issue with the scopes I was providing to the authorization endpoint. The scopes profile, openid, and offline_access should be specified to allow some features of Microsoft's Graph API to function properly. In my case, it was the offline_access scope that did the trick. Also note that these scopes cannot be added to the authorization token request, at least through the Python MSAL library. These scopes need to be specified during the process of getting the authorization code only, not the token.

Related

Unauthorized error while authenticating Sharepoint REST API using Python

I am trying to download a file from a SharePoint Online data library via REST API which uses a multi-factor ADFS authentication, so far I found these posts (Post1, Post2) which talk about sending a SAML request to STS to receive a security token from https://login.microsoftonline.com/extSTS.srf, I have found multiple examples online which uses the same method to authenticate their requests. However, when I send the SAML request to the above Microsoft URL, I receive the error below.
AADSTS50126: Error validating credentials due to invalid username or password.
I have appropriate access to the SharePoint data library as I was able to get a valid response to an API request (to check available lists and not for authentication) when using a browser with authenticated session. Any idea on what I might be doing wrong or even if authentication is possible for MFA secured SharePoint library.
There is no official word in any Microsoft Documentation to confirm this. But MFA account + AAD token is not compatible.
You have to use a service account (username/password) without MFA enabled for it. This will work when you invoke the SPO web api using the service account for getting tokens.
When you have a browser session in open state, the token will be available in cookies & you will be able to access the library without issue. The same applies to POSTMAN or SOAP-UI testing.
Because MFA needs user interaction, this is not possible. Refer this github issue: Trouble spo login with an account with multi-factor authentication
We do "Application User" concept in Dynamics CRM for the same approach. Read more

Obtaining `gmail.compose` privileges for single G Suite email account to send emails via GMail API

I am trying to compose drafts programmatically via the GMail API, using this tutorial and the following line of code:
service.users().drafts().create(userId=user_id, body=message).execute()
but I receive the following error:
An error occurred: <HttpError 403 when requesting https://www.googleapis.com/gmail/v1/users/me/drafts?alt=json returned "Insufficient Permission">
Note that directly sending messages with gmail.send privileges does not work for me - I want to thread messages.
In the API console, I tried enabling the following scope ../auth/gmail.compose, but there is a warning message that Because you've added a sensitive scope, your consent screen requires verification by Google before it's published.
I have submitted my app for verification, but I just received an email stating that "We've extended the deadline to fully complete your verification from May 15th to June 26th, 2019".
Actually, no users will use my G Suite email accounts (so my app cannot be used to spy on their messages) and I only need access to a single email account info#example.com to send notifications to users who use my site on example.com.
Is there any way to get server-side access to my info#example.com account using my password and programmatically draft messages without having to go through the lengthy and unnecessary app verification process?
It turns out that you can have an "internal", rather than a client facing "public" app, for which all GMail scopes are automatically available.
Here is the response from the Google team that describes the steps (it worked for me):
It appears your app is only used by the people in your domain.
If this is correct, please reply to this email to confirm that is the
case. We will then reject your request so that you are able to update
your project from public to internal.
In addition, you will need to associate your project with your
organization by following the steps below:
If you have not already done so, create an Organization by following
the Quickstart Using Organizations instructions.
Migrate the project into the organization you created as shown in
Migrating Existing Projects into the Organization. Once you have
associated your project with your organization, you and the project
users in your organization can use the app to directly access OAuth
scopes. No verification will be required.

Google Calendar API Python Authorization

I've requested access to an OAuth key through the google api console for the calendar api. I've also set my scope up to match the read/write permission setting, but during testing - had authenticated with the "read-only" permissions. Now when I'm testing to insert an event into my calendar, I receive the error "Insufficient Permission". **I'm using python for all of this.
I've tried resetting the client_secret, disabling the api (and renabling), as well as adjusting the auth url.... but to no avail.
Any advice on how to change my permissions in order to create events?
To fix it , I had to revoked access to the app at https://accounts.google.com/IssuedAuthSubTokens and retired after then I was able to access the API correctly.
Despite having the scope in the list, and the scope showing up on Google's OAuth2 grant page, the additional scope wasn't granted.

Authentication with Azure Active Directory - how to accept user credentials programmatically

Is there any way to login via web application or web api to Azure Active Directory (with AD credentials) using my own username and password page which is hosted outside of Azure?
From my investigation it seems there is no programmatic way to send username and password to authenticate users with Azure AD (if you hosted an app outside of Azure)
Not sure if they consider this to be a security hole of some sort (i dont think it is it https is enforced?)
Seems like you can only authenticate users by going through the code grant (which means popping out of our application to sign on to an external site).
Ultimately I want to create a python flask api that can authenticate against Azure AD directly if possible.
I have done this in the past (with other auth systems) with the Oauth grant_type=password to send username and pass, but dont think this is supported in Azure AD (correct me if im wrong?)
I know grant_type=client_credentials is supported, but that seems like its service to service auth, which is not quite what im after
http://msdn.microsoft.com/en-us/library/azure/dn645543.aspx
If its not possible to have a login page hosted outside of Azure for this, is it even possible to have one inside of Azure, seems like from examples here:
http://msdn.microsoft.com/en-us/library/azure/bc8af4ff-66e7-4d5b-b3d4-c33d2c55d270#BKMK_Browser
There is no custom login page with a password field .. (only open id logins it seems)
The Resource Owner Password Credentials Grant (grant_type=password) flow is supported by Azure Active Directory. However, before using it, consider if it is truly required. As it says in the OAuth 2.0 RFC:
The resource owner password credentials (i.e., username and password) can be used directly as an authorization grant to obtain an access token. The credentials should only be used when there is a high degree of trust between the resource owner and the client (e.g., the client is part of the device operating system or a highly privileged application), and when other authorization grant types are not available (such as an authorization code).
If you have determined that the other supported flows will definitely not work for your scenario, then also be sure to follow the second bit of advice in the RFC:
Even though this grant type requires direct client access to the resource owner credentials, the resource owner credentials are used for a single request and are exchanged for an access token. This grant type can eliminate the need for the client to store the resource owner credentials for future use, by exchanging the credentials with a long-lived access token or refresh token.
(Emphasis added in both cases.)
There's a .NET and ADAL sample on GitHub that uses this flow, and it should be simple enough to implement in Python: https://github.com/AzureADSamples/NativeClient-Headless-DotNet
Edit: You can host your application anywhere you want, it doesn't need to be on Azure. This applies to all flows.

google contacts api service account oauth2.0 sub user

I am trying to use the Google Contacts API to connect to a user's contact information, on my Google apps domain.
Generating an access_token using the gdata api's ContactsService clientlogin function while using the API key for my project works fine, but I would prefer to not store the user's credentials, and from the information I have found that method uses OAuth1.0
So, to use OAuth2.0 I have:
Generated a Service Account in the developer's console for my project
Granted access to the service account for the scope of https://www.google.com/m8/feeds/ in the Google apps domain admin panel
Attempted to generate credentials using SignedJwtAssertionCredentials:
credentials = SignedJwtAssertionCredentials(
service_account_name=service_account_email,
private_key=key_from_p12_file,
scope='https://www.google.com/m8/feeds/',
sub=user_email')
The problem I am running into is that attempting to generate an access token using this method fails. It succeeds in generating the token when I remove the sub parameter, but then that token fails when I try to fetch the user's contacts.
Does anyone know why this might be happening?

Categories