I am trying to authenticate an Azure app that has application-level permissions. All the permissions have been granted by an admin, and the app has both a client id and a client secret. I'm running the following code based on the Daemon-api documentation from Microsoft graph:
import msal
config = {
"authority": "https://login.microsoftonline.com/organizations",
"client_id": CLIENT_ID,
"scope": ["https://graph.microsoft.com/.default"],
"redirect_uri": REDIRECT_URI,
"client_secret": CLIENT_SECRET
}
app = msal.ConfidentialClientApplication(
config["client_id"], authority=config["authority"],
client_credential=config["client_secret"] )
result = app.acquire_token_silent(config["scope"], account=None)
import logging
if not result:
logging.info("No suitable token exists in cache. Let's get a new one from AAD.")
result = app.acquire_token_for_client(scopes=config["scope"])
If I print result though, it says the following:
{'error': 'unauthorized_client',
'error_description': "AADSTS700016: Application with identifier [IDENTIFIER] was not found in the directory 'microsoft.com'. This can happen if the application has not been installed by the administrator of the tenant or consented to by any user in the tenant. You may have sent your authentication request to the wrong tenant.\r\nTrace ID: [TRACE ID]\r\nCorrelation ID: [CORRELATION ID]\r\nTimestamp: 2019-08-28 17:14:39Z",
'error_codes': [700016],
'timestamp': '2019-08-28 17:14:39Z',
'trace_id': [TRACE ID],
'correlation_id': [CORRELATION ID],
'error_uri': 'https://login.microsoftonline.com/error?code=700016'}
The app has existed for several days and as I've mentioned, it has had all its permissions authorized by an admin. How come I'm still getting an "unauthorized" error? I check my id and secret, they're correct.
I wonder if it might have something to do with the fact that the error message says it's being sent to the microsoft.com directory? But the only microsoft information I provide is in authority and scope which the api says is needed as-is. I don't see anywhere to provide a directory id. Could that be the issue? If so, how would I rectify it?
Authority field in your config should be
https://login.microsoftonline.com/<directory_id>
Related
Due to the deprecation of some of MS's services, I need to migrate the login method for an unattended script. The script is currently set up to log in to the service using Basic Auth username/password, but now must go through something like MSAL to accomplish this.
Again, this will be an unattended script so it cannot accommodate any interactive prompts.
According to docs, ROPC (while "not recommended") is documented as not requiring any UI. However, when I try to acquire an access token using this method, I get the following:
>>> app = msal.PublicClientApplication(client_id, authority=f'https://login.microsoftonline.com/{tenant_id}')
>>> app.acquire_token_by_username_password(username, passwd, scopes=['Mail.ReadWrite'])
{
'error': 'invalid_grant',
'error_description': "AADSTS65001: The user or administrator has not consented to use the
application with ID '...' named '...'. Send an interactive authorization request for this
user and resource.\r\n...",
'error_codes': [65001],
...,
'suberror': 'consent_required'
}
I have also tried to use the API directly:
POST
https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token
body:
{
"client_id": "{client_id}",
"scope": "https://graph.microsoft.com/mail.readwrite",
"username": "{username}",
"password": "{password}",
"grant_type": "password"
}
Response same as above.
I have set Delegated permissions in the App registration (but there doesn't seem to be a way to grant admin consent here).
The response message suggests this type of request requires an interactive prompt, but the documentation explicitly states this is a non-UI authentication flow.
What am I missing?
I tried to reproduce the same in my environment and got the same error as below:
The error usually occurs if the API permissions granted to the Azure AD Application is not consented by the Global Admin.
To resolve the error, make sure to Grant Admin Consent to mail.readwrite permission like below:
After Granting the Admin Consent, I am able to generate the access token successfully like below:
https://login.microsoftonline.com/TenantID/oauth2/v2.0/token
client_id:f2e61f2e-7340-4f37-9dac-XXXXXX
scope:https://graph.microsoft.com/mail.readwrite
username:rukadmin#XXXX.onmicrosoft.com
password:****
grant_type:password
Alternatively, you can make use of the below endpoint and sign in as Global Admin and Accept the consent on behalf of organization like below:
https://login.microsoftonline.com/TenantID/adminconsent?client_id=ClientID
You can also make use of Interactive Grant Type and allow the users to consent to the application accessing their account by doing the below setting:
Go to Azure Portal -> Enterprise Application -> User Settings -> Go to Consent and permissions
I am trying to validate user purchase with the token received from the client (internal release).
For that I am using Python script with Google Python API Client (https://github.com/googleapis/google-api-python-client).
import httplib2
from oauth2client.service_account import ServiceAccountCredentials
token = "token received from the client"
http = httplib2.Http(timeout=self.http_timeout)
credentials = ServiceAccountCredentials.from_json_keyfile_name(
"./service_account.json", "https://www.googleapis.com/auth/androidpublisher"
)
http = credentials.authorize(http)
result = build("androidpublisher", "v3", http=http)\
.purchases()\
.products()\
.get(packageName="<package name>", productId="<subscription id>", token=token)\
.execute(http=http)
The response I am getting from this call is:
HttpError 401 when requesting https://www.googleapis.com/androidpublisher/v3/applications/<package name>/purchases/products/<subscription id>/tokens/<token>?alt=json returned "The current user has insufficient permissions to perform the requested operation."
The service user being used is give admin permissions to the account (for the sake of the test) in Google Play Console, and set to be "Project Owner" in "Google Cloud Console" console (for the sake of the test again).
What seems to be wrong here?
The 'Owner' permissions are sufficient to receipt validation [Source].
The error you're getting is most likely a propagation issue where it can actually take ~24hrs for the service credentials to go into effect throughout the system.
I'm trying to set up a Google apps script API executable with Server to server auth for a Python micro-service I'm setting up.
Using the Quickstart, I was able to make it work via Auth2, but I was unable to make it work with a service account. I gave access to script and spreadsheet to service account email. Project ID in client secret JSON matches the project ID of the app scripts. I deployed it as an API executable just the same.
This is my code below (although I don't think the code is the issue):
from oauth2client.service_account import ServiceAccountCredentials
from httplib2 import Http
from googleapiclient.discovery import build
scopes = [
'https://www.googleapis.com/auth/drive',
'https://www.googleapis.com/auth/script.external_request',
'https://www.googleapis.com/auth/script.storage',
'https://www.googleapis.com/auth/spreadsheets',
'https://www.googleapis.com/auth/userinfo.email'
]
credentials = ServiceAccountCredentials.from_json_keyfile_name('client_secret.json', scopes)
http_auth = credentials.authorize(Http())
service = build('script', 'v1', http=http_auth)
request = {'function': 'testApi'}
response = service.scripts().run(body=request, scriptId='SCRIPT_ID').execute()
print(response)
The testApi function in my App Script is a simple function that returns "It works".
I keep getting that the user does not have permission (403) when using personal account, or even 500 when using organization (G Suite account).
As mentioned earlier, the Quickstart tutorial from Google documentation worked, but this is not using a service account.
Has anyone made Google Apps Scripts API executable working with a server to server auth account flow?
You may want to check this tutorial about Using Google Service Accounts with Google Apps Script. This sample code shows how to use OAuth in Google Apps Script using Service Accounts.
For this code to work, you need to create a Google Service account with domain-wide delegation, substitute the private key and client client email with the actual values and also add the Client Id to your Google Apps admin console with the Drive API Scope. The OAuth 2.0 access tokens are stored in the Script Properties.
var JSON = {
"private_key": "Your Private Key",
"client_email": "serviceacount#project-ctrlq.iam.gserviceaccount.com",
"client_id": "1234567890",
"user_email": "amit#labnol.org"
};
function getOAuthService(user) {
return OAuth2.createService("Service Account")
.setTokenUrl('https://accounts.google.com/o/oauth2/token')
.setPrivateKey(JSON.private_key)
.setIssuer(JSON.client_email)
.setSubject(JSON.user_email)
.setPropertyStore(PropertiesService.getScriptProperties())
.setParam('access_type', 'offline')
.setScope('https://www.googleapis.com/auth/drive');
}
function getUserFiles() {
var service = getOAuthService();
service.reset();
if (service.hasAccess()) {
var url = 'https://www.googleapis.com/drive/v2/files?pageSize=1';
var response = UrlFetchApp.fetch(url, {
headers: {
Authorization: 'Bearer ' + service.getAccessToken()
}
});
Logger.log(response.getContentText());
}
}
function reset() {
var service = getOAuthService();
service.reset();
}
Also, if you are getting the 403 Insufficient permission error, it is likely because the application is requesting access to API scopes that are not authorized in the Google Apps admin console. The invalid_grant error is likely due to incorrect date and time settings of the server that is hosting the application.
I am trying to write a script on Python that fetches my friend list from facebook. To fetch data, I need to get the access token. I am using requests_oauthlib package to achieve the same. Since I am not writing a web application, I have not used local webserver(no redirect url). I choose to use Resource owner password credentials grant type. I am getting error.
This is my code:
from requests_oauthlib import OAuth2Session
from oauthlib.oauth2 import LegacyApplicationClient
FACEBOOK_APP_ID = '**********'
FACEBOOK_APP_SECRET = '*********'
username = 'Aman Mittal'
password = '****'
token_url = "https://graph.facebook.com/oauth/access_token"
oauth = OAuth2Session(client=LegacyApplicationClient(client_id=FACEBOOK_APP_ID))
oauth_access_token = oauth.fetch_token(token_url, client_secret=FACEBOOK_APP_SECRET,username=username, password=password, client_id=FACEBOOK_APP_ID)
When I run the script, it shows error - 'Missing access token parameter'
I went through traceback and realized that access token received is this:
{"error":{"message":"Missing redirect_uri parameter.","type":"OAuthException","code":191,"fbtrace_id":"CUSmQKT8YGb"}}
First of all, I don't understand while using Legacy Application client(Resource Owner password credentials grant type ), why do I need redirect uri?
If I do choose to start a webserver alongside using web.py or something else. How do I register it on Facebook? or Do I even need to?
PS. I am new to both Python and posting on Stack Overflow. Please try to explain with details and forgive me if I have committed any stupid mistake.
Facebook does not support the OAuth 2.0 Resource Owner Password Credentials grant type.
I am trying to call a Azure ARM Rest API to create a resource group. I am passing tenant_id, client_id and client_secret to get the access token which will be later used as authorization header. My code is like below. The application ID is the client ID off the application and application secret is the key which is generated after selecting the time duration.
import adal
import requests
token_response = adal.acquire_token_with_client_credentials(
'https://login.microsoftonline.com/' + '<tenantId>',
'<ApplicationId>',
'<Application Secret>'
)
access_token = token_response.get('accessToken')
endpoint = 'https://management.azure.com/subscriptions/xxxx/resourcegroups/resourcename?api-version=2015-01-01'
headers = {"Authorization": 'Bearer ' + access_token}
json_output = requests.put(endpoint,headers=headers).json()
print json_output
But this is throwing me an error as below
{u'error': {u'message': u"The access token is from the wrong issuer 'https://sts
.windows.net/xxx/'. It must match the tenant 'h
ttps://sts.windows.net/xxx/' associated with th
is subscription. Please use the authority (URL) 'https://login.windows.net/xxx' to get the token. Note, if the subscription is
transferred to another tenant there is no impact to the services, but informatio
n about new tenant could take time to propagate (up to an hour). If you just tra
nsferred your subscription and see this error message, please try back later.",
u'code': u'InvalidAuthenticationTokenTenant'}}
What does this error mean and am I passing the right credentials. If I use the credentials mentioned in the error, I get another error which says application with mentioned client_id not found.
As the message says you need to go against login.windows.net instead of login.microsoftonline.com:
token_response = adal.acquire_token_with_client_credentials(
'https://login.windows.net/' + '<tenantId>',
'<ApplicationId>',
'<Application Secret>'
It seems that there is some problem with your AD application. To authenticate Azure ARM you need a AD with service principal.
You can refer to Create Active Directory application and service principal using portal or Authenticating a service principal with Azure Resource Manager to create a new AD application. Use these info in your code and try again.
It's the difference between common tenant and separate tenant which causes this issue.
Would you please see my answer in another thread Azure Active Directory Authorization "The access token is from the wrong issuer ' ?
Hope this helps.
In client credentials use
"https://management.core.windows.net/"
instead of https://login.microsoftonline.com/ in your code.
token_response = adal.acquire_token_with_client_credentials(
'https://management.core.windows.net/' + '<tenantId>',
'<ApplicationId>',
'<Application Secret>'
I fixed same problem with this.
Thanks,
Bhushan