I am trying to access the MSGraph API using the ADAL python package. Here is a code snippet for how I am acquiring the authorization token.
authority = "https://login.microsoftonline.com/" + tenant
RESOURCE = "https://graph.microsoft.com"
context = adal.AuthenticationContext(authority)
#Use this for Client Credentials
token = context.acquire_token_with_client_credentials(
RESOURCE,
client_id,
client_secret
)
I am getting a token back after making this request in this form:
{
"tokenType": "Bearer",
"_clientId": <clientID>,
"_authority": "https://login.microsoftonline.com/<tenant>",
"expiresIn": 3599,
"isMRRT": true,
"accessToken": <token>,
"resource": "https://graph.microsoft.com",
"expiresOn": "2017-07-13 16:38:11.591687"
}
Now, I am using this token in order to make an http request, like so:
request_url = 'https://graph.microsoft.com/v1.0/users'
h = {'Authorization': 'Bearer ' + token['accessToken']}
response = requests.get(url = request_url, headers = h)
I'm getting a response back like this:
{
"error": {
"code": "Authorization_RequestDenied",
"message": "Insufficient privileges to complete the operation.",
"innerError": {
"request-id": "f8c634c0-e23a-4f46-8e39-70ed9e35ef68",
"date": "2017-07-13T19:38:13"
}
}
}
My question is: Why? I have applied the necessary permissions in the Microsoft App Registration portal. I have also managed to get an instance of this request working use the Microsoft Graph Python connect sample, so I know I'm able to access the data. Why can I not get this instance working? Thank you.
The error shows the access token didn't have enough permission to execute the list users api . You could grant Read all users' full profiles (User.Read.All scope) application permission for your app :
Add Read all users' full profiles application permission of microsoft graph in your azure ad application :
Grant that application permission by clicking Grant Permissions button in above screenshot with admin account of your AAD .
Using client credential flow to acquire access token for microsoft graph as your code . After you get the access token , you could decode the token using online tool, you should find User.Read.All in roles claim .
Send a list users api with access token .
Please let me know if it helps.
Related
problem description:
we are getting (#100) Missing permissions errors while extracting facebook account ads
insights data using programmatically generated access tokens using Graph API in python.
later we generated access tokens in the app with ads_read and insights_read permission and we can able to extract the data successfully.
questions:
1.how can we generate access tokens with permissions programmatically using Graph API in python?
2.which token is advisable to extract data for ad account insights?
error message:
{
"error": {
"message": "(#100) Missing permissions",
"type": "OAuthException",
"code": 100,
"fbtrace_id": "A4vPClDlI__dFmxxhiVVGRG"
}
}
access token generation code sample:
import requests
def get_fb_token(app_id, app_secret):
url = 'https://graph.facebook.com/oauth/access_token'
payload = {
'grant_type': 'client_credentials',
'client_id': app_id,
'client_secret': app_secret
}
response = requests.post(url, params=payload)
return response.json()['access_token']
app_id = 'XXXXXXXXXXXXXXX'
app_secret = 'XXXXXXXXXXXXXXXXX'
data_request = get_fb_token(app_id, app_secret)
print(data_request)
Note:
we have also tried passing scope:ads_read, but we are getting the same error.
we have also tried Facebook -SDK package, but we are getting the same access tokens.
Simplest: If your BM has access to that ad account
Use System User flow.
Create A System User.
Generate&Copy the long lived token from BM page and paste it into your server. (This will not expire ever)
Assign the ad accounts(or any other assets) you wanna access either programmatically or manually.
Standard Apporach: Oauth2 flow.
When users get onboarded to your system, ask them to sign in via FB and send the short lived token to Backend servers. OAuth2
Exchange the short lived token for long lived one with FB. Long lived tokens have expiry of 60days.
I'm trying to implement Google sign in using DRF and dj_rest_auth.
I've set up 'django-allauth' with Google as provider and the sign in process works in the web browser.
I need to connect an android app with my backend. I've created API endpoints which will require authentication.
According to the docs, code is required in order to complete authentication and receive the token.
After doing some research, I found that code required by dj_rest_auth can be obtained by visiting:
https://accounts.google.com/o/oauth2/v2/auth?redirect_uri=<YOUR CALLBACK URL>&prompt=consent&response_type=code&client_id=<YOUR CLIENT ID>&scope=openid%20email&access_type=offline
However, even after passing code returned in the query param (after decoding from URL format), the following error is shown:
Error retrieving access token: b'{\n "error": "invalid_grant",\n "error_description": "Bad Request"\n}'
To see if I can log in with a recent access token, I signed in with my Google account from the homepage , copied the access token from the admin section and submitted it to the endpoint http://localhost:8000/dj-rest-auth/google/. I was able to receive the auth token generated by dj_rest_auth.
I need help in getting the auth token by providing code in the post request.
My code:
# urls.py
...
path('dj-rest-auth/', include('dj_rest_auth.urls')),
path('dj-rest-auth/registration/', include('dj_rest_auth.registration.urls')),
path('dj-rest-auth/google/', home.GoogleLogin.as_view(), name='google_login'),
...
# views.py
from allauth.socialaccount.providers.google.views import GoogleOAuth2Adapter
from allauth.socialaccount.providers.oauth2.client import OAuth2Client
from dj_rest_auth.registration.views import SocialLoginView
class GoogleLogin(SocialLoginView):
adapter_class = GoogleOAuth2Adapter
callback_url = 'http://localhost:8000/accounts/google/login/callback/'
client_class = OAuth2Client
...
References:
Google Social Authentication with dj-rest-auth #220
Minimal example for SPA implementation of social login #147
Please help me.
Did you create your authentication keys on Google Cloud and add them in settings.py ?
It looks like that for me in settings :
SOCIALACCOUNT_PROVIDERS = {
"google": {
# For each OAuth based provider, either add a ``SocialApp``
# (``socialaccount`` app) containing the required client
# credentials, or list them here:
"APP": {
"client_id": os.environ.get("GOOGLE_CLIENT_ID"),
"secret": os.environ.get("GOOGLE_SECRET_KEY"),
"key": ""
},
# These are provider-specific settings that can only be
# listed here:
"SCOPE": [
"profile",
"email",
],
"AUTH_PARAMS": {
"access_type": "online",
}
}}
I have built a python application to access read only Power BI Rest API’s. I am automating the collection of tenant activity. However despite configuring my Azure App and using the service principal to generate an access token, the response I receive from the API request is one of an unauthorised response:
{"error": {"code": "PowerBINotAuthorizedException", "pbi.error": {"code":
"PowerBINotAuthorizedException", "parameters": {}, "details": [], "exceptionCulprit": 1}}}
I have found a number of similar issues posted online, however feel that I have done everything that is suggested but am still not able to get it working. I would appreciate any guidance.
The steps that I have taken are:
Configured an Azure App, adding the Application Permission for Power Bi Service-Tenant.Read.All
Screenshot of App Settings in Azure Portal
Requested my access token based upon the Client Credentials Flow using my app's client_ID and client_Secret as documented in the below link:
https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-client-creds-grant-flow
I successfully receive a token using the script below:
import requests
azureTenantID = "xxxxxxxxxxxxxxxxx"
azureClientId = "xxxxxxxxxxxxxxxxx"
azureClientSecret = "xxxxxxxxxxxxxxxxxx"
url = f"https://login.microsoftonline.com/{azureTenantID}/oauth2/v2.0/token"
payload = {
"grant_type": "client_credentials",
"client_id": azureClientId,
"client_secret": azureClientSecret,
"scope": "https://analysis.windows.net/powerbi/api/.default"
}
# Header HAS to be x-www-form-urlencoded for MS to accept it.
headers = {'Content-Type': 'application/x-www-form-urlencoded'}
# Return POST content as JSON.
r = requests.post(url, data=payload, headers=headers).json()
# Grab the access token.
response = r.get("access_token")
# Concatenate with Bearer string
access_token = "Bearer {r['access_token']}"
Configured my Power BI Tenant Settings to enable Service Principals to use API's.
Screenshot of Admin API Setting
Screenshot of Developer API Setting
Note that I added the Service Principal as a member of the Security Group for which both of these settings are enabled
Execute my Get request to the API
The followings script returns a good response when I take an access token from the Power BI REST API Documentation's 'Try it out' feature, but not when I generate the token as above.
import requests
# Initialise parameters.
url = "https://api.powerbi.com/v1.0/myorg/admin/groups?$top=1000&$expand=datasets,dataflows,reports,users,dashboards"
headers = {'Authorization': get_access_token2()}
# Get response.
response = requests.get(url, headers=headers)
response = response.json()
Any assistance would be appreciated !
I just went through this exact scenario that you described, and in the end we had to engage Microsoft support to solve it.
Although extremely counter intuitive, if the app that you create for your service principal authentication has any Power BI permissions assigned to it then the access token that is generated (when passed to Power BI REST Admin API) will return an error response that reports PowerBINotAuthorizedException.
To be even more specific, if the access token that you pass to the Power BI API has a roles key/value pair, then you will get a PowerBINotAuthorizedException.
In your case, the issue is easier because you have listed out what permissions you granted. You mentioned that you Configured an Azure App, adding the Application Permission for Power Bi Service-Tenant.Read.All. In order to resolve this issue, you will need to remove that permission.
For future readers, you can troubleshoot this by decoding your access token using a JWT token decoder like one found at jstoolset.com. If your app has permissions allocated to the scope that you have requested (https://analysis.windows.net/powerbi/api/.default is the typical Power BI scope that you request in your authorization) and you decode your JWT token then you will see a roles key/value pair. The presence of this roles is essentially the issue. It does not matter that the values there might match up to the Required Scope in the Power BI REST Admin API documentation. It was described to us as if there is a roles value in your access token then when the token is presented to the Power BI API the roles that are granted are attempted to be used, which ultimately results in a PowerBINotAuthorizedException because service principals are not allowed to use a certain role.
If you have an app that you have removed all permissions from, but still has a value coming through in your access token for the roles key/value pair, then I would suggest starting with a new app with no permissions allocated to it, and simply add the new app to the existing security group that you originally created. This is how we realized that this truly was the issue, and were then able to reconcile from there.
EDIT: Microsoft has now updated their API documentation on the relevant endpoints to reflect this information. For example, in Admin - Groups GetGroupUsersAsAdmin the Required Scope now reads:
Tenant.Read.All or Tenant.ReadWrite.All
Relevant only when authenticating via a standard delegated admin access token. Must not be present when authentication via a service principal is used.
Here's my problem:
I have a 365 Family OneDrive subscription with 3 members, my account being the admin.
I am trying to build a python application to read/extract the content of the files I have on this onedrive space based on specific criterias. I want to build it as a command line application, running locally on my PC. I am aware some tools may exist for this but I'd like to code my own solution.
After going through tons of different documentation, I ended up doing the following
Registered my application on the Azure portal
Granted some permission on the Microsoft Graph API (User.read, Files.Read and Files.ReadAll)
Created a secret
Grabbed the sample code provided by Microsoft
Replaces some variables with my Client_Id and Secret
Ran the code
The code returns an access token but the authorization requests fails with 401 - Unauthorized: Access is denied due to invalid credentials.
Here's the Python code I'm using.
import msal
config = {
"authority": "https://login.microsoftonline.com/consumers",
"client_id": "<my client ID>",
"scope": ["https://graph.microsoft.com/.default"],
"secret": "<My secret stuff>",
"endpoint": "https://graph.microsoft.com/v1.0/users"
}
# Create a preferably long-lived app instance which maintains a token cache.
app = msal.ConfidentialClientApplication(
config["client_id"], authority=config["authority"],
client_credential=config["secret"],
)
result = None
result = app.acquire_token_silent(config["scope"], account=None)
if not result:
result = app.acquire_token_for_client(scopes=config["scope"])
if "access_token" in result:
# Calling graph using the access token
graph_data = requests.get( # Use token to call downstream service
config["endpoint"],
headers={'Authorization': 'Bearer ' + result['access_token']}, ).json()
print("Graph API call result: ")
print(json.dumps(graph_data, indent=2))
else:
print(result.get("error"))
print(result.get("error_description"))
print(result.get("correlation_id")) # You may need this when reporting a bug
According to the error message, I'm obviously missing something in the authorization process but can't tell what. I'm not even sure about the Authority and Endpoints I should use. My account being a personal one, I have no tenant.
Do I need to set-up / configure some URI somewhere?
Any help would be welcome.
Thank you in advance.
In your client app you need to store the token that you are getting from the MSAL. and then send the token with an authorized request.
For OneDrive, download the OneDrive for python. You can see the different option for Authentication.
The reason you are getting an access token, ID token, and a refresh token is because of the flow you're using. My suggestion is to review the flows for a better understanding of how the authentication process works and what will be returned accordingly. You can use this MSAL library for python.
I have a Python application that accesses Youtube-Data-API v3.
After the program runs for an hour, it throws an error suggesting the access token has expired.
How can I persist the token for a longer period?
There is now way to extend the time for access token. They get expired after an hour. The only way of using a token is to get a new token using refresh_token provided by the api.
First you get offline token by setting access_type to offine while authenticating the user.
{
'response_type': 'code',
'client_id': 'client_id',
'redirect_uri': '...',
'access_type':'offline',
'scope': 'https://www.googleapis.com/auth/youtube.readonly',
}
you will get refresh_token, access_token, id_token along with expiry and some other fields which you can save in you database and fetch later when needed.
Before using the access_token you check if it is valid
creds = google.oauth2.credentials.Credentials(access_token,refresh_token=refresh_token,id_token=id_token,token_uri=token_uri,client_id=client_id,client_secret=client_secret,scopes=scopes,expiry=expirytime)
if creds.valid == False:
// Refresh to get the new token
req =google.auth.transport.requests.Request()
creds.refresh(req)
// Now Save new Credentials from "creds" so that you can use later.
After verifying the access_token you can now query youtube data api requests
youtube = googleapiclient.discovery.build(
"youtube", "v3",credentials=creds)
req = youtube.videos().getRating(id="xxxxxxxxx")
resp =req.execute()
When you create O-Auth2 credentials, you need to select "Web App" which is what I think you're trying to create. (A website, correct?).
The "Desktop-App" option is for if you want to make a desktop application, not a website.
Desktop applications and web applications handle redirect uris differently, which is what's causing your issue.