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.
Related
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.
I’m trying to send a photo saved on my pc through the SkyBiometry API but it says error_message: MISSING_ARGUMENTS - access_token is missing and I don’t know how to fix it.
This is the code I used:
auth_headers = {
‘api_key’: ‘my_api_key’,
‘api_secret’: ‘my_api_secret’,
‘Content-Type’: ‘application/json’
}
url = ‘http://api.skybiometry.com/fc/faces/detect’
files = {
‘source’: open(r"C:\Users\Diego\OneDrive\Desktop\API\img\happy.png", “rb”)
}
data = {
‘timeout’: 60
}
response = requests.post(url, files=files, data=data, headers=auth_headers)
print(response.json())
You need to get an API key from SkyBiometry it sounds like. See section 1.1 below
https://skybiometry.com/documentation/
Every call to the API is required to be authorized, which basically means that you must sign up and obtain API access keys before accessing the service. Once that is done, you are ready to go coding.
SkyBiometry provides two ways for the client to authenticate himself:
*api_key and api_secret – by choosing this method every call to API must include api_key and api_secret. By using this fields we can map API call to the API user.
api_key and domain authentication – there are some situations when disclosing api_secret is not an option (like using java script client code or flash). Instead of disclosing api_secret, API user can choose domain authentication method. During the call there is no need to specify api_secret, instead user will be authenticated by calling domain, which will be compared to specified in user profile settings.
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.
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.