Google DFA Reporting - Bad Request (400) Invalid ProfileID - c#

I am trying to use Double Click for Advertisers API (DFA). I've explored the "Try it" and tested the Api through google developers console and it works as expected. I was able to catch the Authorization token and perform get and post requests(via browser and programmatically).
However when I try to do exactly the same, programmatically using the donet api 2.4, the Authentication Token that is generated doesn't allow me to do any requests, it always returns HTTP 400 Bad Request with the reason Invalid ProfileID.
I'm not sure if the client_secrets.json are correct, but I've created it using the same email account that has access to the reports.
{
"installed": {
"client_id": "<client_id>.apps.googleusercontent.com",
"project_id": "<project_id>",
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://accounts.google.com/o/oauth2/token",
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
"client_secret": "<secret>",
"redirect_uris": [ "urn:ietf:wg:oauth:2.0:oob", "http://localhost" ]
}
}
I used the credentials code below:
private static readonly IEnumerable<string> scopes = new[] {
DfareportingService.Scope.Dfareporting,
DfareportingService.Scope.Dfatrafficking
};
credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
GoogleClientSecrets.Load(stream).Secrets,
scopes,
"dfa-user", CancellationToken.None,
new FileDataStore("DfaReporting.Samples")).Result;
The generated token gives me the following info:
{
"issued_to": "<client_id>.apps.googleusercontent.com",
"audience": "<client_id>.apps.googleusercontent.com",
"scope": "https://www.googleapis.com/auth/dfareporting https://www.googleapis.com/auth/dfatrafficking",
"expires_in": 3073,
"access_type": "offline"
}
The libraries I mentioned above are available on GitHub: https://github.com/googleads/googleads-dfa-reporting-samples/tree/master/dotnet/v2.4
What am I missing?

First make sure that you have set this up correctly.
You must have a DCM account. See Advertisers/Agencies for signup information.
Your DCM account must be enabled for API Access. Contact your DoubleClick representative or the DCM support team for assistance. (dcm-support#google.com)
You must have a user profile with access to this account. Have your DCM account administrator create a user profile associated with this account.
It sounds to me that who ever you are trying to use to authenticate doesn't have access to the profile you are trying to request for.
In response to comment:
If you are using the .net client library I don't understand why you would be calling the following request manually as you have commented
https://www.googleapis.com/dfareporting/v2.4/userprofiles?access_token=<access token>
I also don't understand how if you are using the .Net client library and the following request could return invalid profile id when you aren't sending one. It might return no profiles if the user doesn't have access to any.
service.UserProfiles.List().Execute();
This might return invalid profile id if the profile id you send it is well not valid.
service.UserProfiles.Get(profileId).Execute();
Running reports
To be able to run a report the user must have access to the profile and the report. Your error message means that the user doesn't have access to that profile you need to either login with a user that has access or grant the user access.
service.Reports.Run(profileId,reportId).Execute();

Related

Get Microsoft accessToken silently

I'm trying to connect to Graph API and get user access token.
My problem is that I don't know how to connect to Graph API with credentials silently (without browser).
I currently use MSLogin() for get access token but it open a browser where you can authorize an AzureAD app to get some access to your account. A library in Java is litteraly what I want in c# https://github.com/Litarvan/OpenAuth
I need something like: MSGraph.ConnectAsync(email, pass).getAccessToken();
Here my current code (Through a browser)
private const string ClientId = "520f6e8e-xxxxxxxxxxxxxxxxxxxx";
private string[] scopes = { "https://graph.microsoft.com/user.read" };
private static AuthenticationResult authResult;
public static IPublicClientApplication PublicClientApp;
private async Task<AuthenticationResult> MSLogin()
{
PublicClientApp = PublicClientApplicationBuilder.Create(ClientId).WithRedirectUri("msal520f6e8e-xxxxxxxxxxxxxxxxxxxxxxxxxxxxx://auth").Build();
authResult = await PublicClientApp.AcquireTokenInteractive(scopes).ExecuteAsync();
return authResult;
}
If you are using Microsoft Graph .NET Client Library you can check documentation with example how to implement username/password authentication flow.
string[] scopes = {"User.Read"};
var usernamePasswordCredential = new UsernamePasswordCredential("username#domain.com", "password", tenantId, clientId);
var graphClient = new GraphServiceClient(usernamePasswordCredential, scopes);
var me = await graphClient.Me.Request().GetAsync();
You can use AcquireTokenByUsernamePassword() for that, see MSDN.
Note however that Microsoft discourages usage of this flow and depending on your AzureAD setup there might be restrictions (i.e. you can aquire tokens only within a certain IP range etc).
Well, you can get the access token silently but not at the first time, First a user must authorize your app by going through Microsoft's Login flow and for your subsequent calls to Microsoft, you can get the access token without the intervention of user.
I would just give a basic idea, without focusing on a specific SDK that you might be using. For which, you can decide which ever method suits your needs.
I assume, you already have your credentials and desired scopes with you, otherwise you need to obtain those.
Formulate a proper URL using the credentials you obtained, plus you need to add an extra scope in the URL which is offline_access. Then you need to redirect the user to Microsoft for the initial authorization.
If the user logs in successfully, Microsoft will redirect the user back to your website with an Authorization Code.
Grab that Authorization Code and exchange it for an Access Token using /oauth2/{version}/token api.
You will receive a response from above call which will contain an Access Token along with a Refresh Token. You need to store the refresh token somewhere for future use.
Now comes the interesting part.
Using the refresh token, you can renew the access token when it expires without user's intervention. You can use oauth2/v2.0/token api with parameters:
client_id={your_client_id}&scope={your_scopes}&refresh_token={refresh_token_obtained}&grant_type=refresh_token&client_secret={your_client_secret}
The resultant response would look something like this:
{
"access_token": "new access token",
"token_type": "Bearer",
"expires_in": 3599,
"scope": "your scopes",
"refresh_token": "refresh token",
}
REF: https://learn.microsoft.com/en-us/graph/auth-v2-user#authorization-request

.Net Microsoft team Meeting API generating access denied token

I have tried to create a Microsoft team API to create an online meeting. I have created an app register in azure with clientId and tenantId. I added permission with the delegate, and in other times in public as a trial as I know delegate is the correct and then create secret, and I tested it in Microsoft explorer it works perfectly now I tried to work with it in c# code I got token. However, I noticed that the token is different from Microsoft explorer, so I got an error in creating event access denied as the token does not have permission.
The second question can I generate a unique link for the meeting for each attendance.
The error I'm receiving is
{
"error": {
"code": "Authorization_RequestDenied",
"message": "Insufficient privileges to complete the operation.",
"innerError": {
"date": "2020-12-03T13:05:33",
"request-id": "cc2dbedc-610e-4d95-a30d-672ff241efa4",
"client-request-id": "cc2dbedc-610e-4d95-a30d-672ff241efa4"
}
}
}
This is happening because Security Defaults is enabled for your tenant.
For each request made to the API, the token changes so the token received in graph explorer will be different from the token received via Code.
Check and try with Auth Request for token and pass the token received to the online meeting API

Create user using Microsoft Graph

How do I create a user using Microsoft graph? For I am having issues with regards to permission failures during a save.
I do have few questions in mind.
Where will the user be created by calling create user API in graph ? Is it in Azure AD or somewhere else ?
I tried calling create user api by passing json and required headers, below is the error I get
Where exactly do I need to set the permission, I have already added permissions in the Application Registration Portal
But when API is executed it shows that I don't have enough permission.
FYI, I have registered the app using the same email id that I am using to test the APIs here https://developer.microsoft.com/en-us/graph/graph-explorer#
If I am not the admin, where exactly do I need to set or request for it ?
In order to create a User via Microsoft Graph, you need to request either Directory.ReadWrite.All or Directory.AccessAsUser.All permission.
Important: Directory.ReadWrite.All and Directory.AccessAsUser.All both require Admin Consent before you can use them. If you're using Graph Explorer then the URI you need to provide your tenant Admin will be generated for you. If you're doing this in your own application, you'll need to construct an Admin Consent URI yourself. You can find more details on this at v2 Endpoint & Admin Consent.
Once you have the proper permissions configured (and consented), you'll want to POST the following JSON body/payload to https://graph.microsoft.com/v1.0/users:
{
"accountEnabled": true,
"displayName": "displayName-value",
"mailNickname": "mailNickname-value",
"userPrincipalName": "upn-value#tenant-name.onmicrosoft.com",
"passwordProfile" : {
"forceChangePasswordNextSignIn": true,
"password": "password-value"
}
}
This will create a user with a temporary password. The user will be asked to set a new password as after as they authenticate for the first time.
Where will the user be created by calling create user API in graph ?
Is it in Azure AD or somewhere else ?
Yes, the user created is in the Azure AD.
I tried calling create user api by passing json and required headers,
below is the error I get
For your error, have you added the request body like the following, and this required admin:
Where exactly do I need to set the permission, I have already added
permissions in the Application Registration Portal
The required permissions to create application:
For the details, please read here.

How to ask user permission in private browser session?

I noticed a very frustrating situation on Google OAuth2 where the email passed is different against the account actually connected to the system. Let me explain better, I wrote this method that ask user permission for access my app to user private Google Calendars:
public static CalendarService OAuth(string userName)
{
string[] scopes = new string[]
{
CalendarService.Scope.Calendar,
CalendarService.Scope.CalendarReadonly
};
try
{
UserCredential credential = GoogleWebAuthorizationBroker.AuthorizeAsync(new ClientSecrets
{
ClientId = "client id Google Developer Console",
ClientSecret = "Secret key Google Developer Console"
},
scopes,
userName,
CancellationToken.None,
new FileDataStore("Stored.Token")).Result;
CalendarService service = new CalendarService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "Application name"
});
return service;
}
catch (Exception ex)
{
Console.WriteLine(ex.InnerException);
return null;
}
}
Now someone already have understood the situation but I want to explain why this procedure is bad for me. Suppose that I want create an application that as the fist screen allow the user to insert personal email, this email should be used by the method OAuth as the parameter userName for ask user permission on Google Browser window.
Until here no problem, the user has entered the email and the application open Google Chrome browser for ask to him the permission to access to private calendars.
But, what's happean if the Google account connected actually in the Chrome browser is different against the email passed?
What's happean if the user that use the application grant the access with a different account connected and him doesn't noticed this?
The application will use a different account for upload the data and the user can thought that stay upload data on personal calendar. Someone have work around this situation, maybe opening Chrome, after UserCredential code block in a private browser, and if yes, in this case the token will stored in the folder specificed: AppData\Roaming\Stored.Token?
Practice example:
1. User type private email in my app: foo#gmail.com
2. App launch Chrome session and ask User permission, account acctually connected bar#gmail.com
3. User doesn't noticed this situation and grant my app to access to bar#gmail.com
4. My app will use bar#gmail.com for upload event, but the user thinks that the app stay using foo#gmail.com
5. The chaos.
Usage of different account can be prevented by performing the OAuth flow and updating private browser session with the granted token and scopes.
Reading through the Basics of Authentication, we have:
1. Registering your app
Every registered OAuth application is assigned a unique Client ID and Client Secret which should never be shared. When you register your application, you can fill out every piece of information except the Authorization callback URL, also considered as the most important piece of setting up your application. It's the callback URL where a user will be redirected after successful authentication.
2. Accepting user authorization
Your client ID and client secret keys come from your application's configuration page which was recommended to be stored as environment variables as shown in the sample code.
<html>
<head>
</head>
<body>
<p>
Well, hello there!
</p>
<p>
We're going to now talk to the GitHub API. Ready?
Click here to begin!</a>
</p>
<p>
If that link doesn't work, remember to provide your own Client ID!
</p>
</body>
</html>
Notice that the URL uses the scope query parameter to define the scopes requested by the application. For the sample code, we requested user:email scope for reading email addresses. After you click on the link you should be taken to Authorization page. and then will be redirected to a route specified in Callback URL. You will be provided with a temporary code value to be added in a POST HTTP request in exchange for an access_token then you'll be able to make authenticated requests as the logged user.
# fetch user information
auth_result = JSON.parse(RestClient.get('https://api.github.com/user',
{:params => {:access_token => access_token}}))
# if the user authorized it, fetch private emails
if has_user_email_scope
auth_result['private_emails'] =
JSON.parse(RestClient.get('https://api.github.com/user/emails',
{:params => {:access_token => access_token}}))
end
erb :basic, :locals => auth_result
And lastly,
3. Implementing "persistent" authentication
As recommended:
Since we're persisting scopes within the session, we'll need to handle cases when the user updates the scopes after we checked them, or revokes the token. To do that, we'll use a rescue block and check that the first API call succeeded, which verifies that the token is still valid. After that, we'll check the X-OAuth-Scopes response header to verify that the user hasn't revoked the user:email scope.
Implementing the code shown in developer github, we now have the authenticated method which checks if the user is already authenticated. If not, the authenticate method is called, which performs the OAuth flow and updates the session with the granted token and scopes.

Facebook Graph API "/userid/feed" returning Blank

I'm using Facebook C# SDK and I can't seem to get feed data back using Graph API.
I've obtained the following extended permissions from the user:
scope=offline_access,publish_stream,publish_checkins,create_event,read_stream,user_about_me,user_events,user_hometown,user_location,user_photos,read_friendlists,read_requests,user_checkins,user_relationships,user_online_presence,user_notes,user_likes,user_work_history
I have an access token for offline access.
I'm able to retrieve userid/friends information without a hitch, but can't seem to get feed data.
I get the following returned:
{
"data": [
]
}
I obtained the token with type="client_cred" if that makes a difference. The process runs with user offline, so I'm not using the "me" alias.
Can someone give some direction on what I'm doing wrong?
A token obtained with type=client_cred means "the application on behalf of itself", rather than "the application on behalf of a specific user". This means that it can only see stuff that's visible to all users. If you want to grab information on behalf of a particular user, you need to use that user's access token that you acquired. Since you asked for offline_access, when you acquire an access token for a user, that token won't expire quickly, and you can keep it around in a database.
FB.init({
appId : 'YOUR APP ID',
status : true, // check login status
cookie : true, // enable cookies to allow the server to access the session
xfbml : true // parse XFBML
});
Once you add this code. Facebook sets a cookie on you domain. The name of the cookie would be fbs_YourAppId .
You can read the cookie and get the access_token.
Alternately you can use a method provided by the Facebook Api Connect.js file to get the feed if the user is logged in.
FB.Api(). Please refer to http://developers.facebook.com/docs/reference/javascript/fb.api/ to know more about the method.
Happy coding :)

Categories