I am new to the Graph API and would like to call my outlook calendars with the event schedules from a daemon application.
When I login to Microsoft account using the email I use to login to Azure I can see my calendar fine and I can also call the Web API using the Graph Explorer.
E.g. the Graph Explorer call:
https://graph.microsoft.com/v1.0/me/calendars
returns my calendar events fine when I am logged in with my Microsoft account.
Now, I would like to be able to access the same API using a service application i.e. without the user login prompt. So I went to the Azure portal, created and registered a new application, gave it Calendar.Read API permission with the administrator's consent and downloaded a quickstart daemon app which makes
await apiCaller.CallWebApiAndProcessResultASync($"{config.ApiUrl}v1.0/users", result.AccessToken, Display);
call which works i.e. it returns a user so that I can see that the
"userPrincipalName": "XYZ#<formattedemail>.onmicrosoft.com"
which is not what the Graph Explorer call returns. The Graph explorer call:
https://graph.microsoft.com/v1.0/users
and returns "userPrincipalName": "myactualemail"
So basically when I make the Graph Explorer call:
https://graph.microsoft.com/v1.0/me/calendars
it returns the calendars' result which is correct.
However, an equivalent daemon API call
await apiCaller.CallWebApiAndProcessResultASync($"{config.ApiUrl}v1.0/users/f5a1a942-f9e4-460b-9c6c-16f45045548f/calendars", result.AccessToken, Display);
returns:
Failed to call the web API: NotFound
Content: {"error":{"code":"ResourceNotFound","message":"Resource could not be discovered.","innerError":{"date":"2021-12-26T16:46:35","request-id":"67ef50e4-bec6-48ae-9e45-7765436d1345","client-request-id":"67ef50e4-bec6-48ae-9e45-7765436d1345"}}}
I suspect that the issue is in the userPrincipalName mismatch between the Graph Explorer and the daemon application, but I am failing to find a solution to this.
Also note that a normal ASP.NET Core sample which requires manual user login works ok. The issue is only with the daemon application.
There is no "me" in your case, so you need to use https://graph.microsoft.com/v1.0/users/user#domain.demo/calendars url.
When you used Graph Explorer to test the api, you've signed in the website, so /me/calendars contained in the request can know who is me and then return correct data to you.
Come back to your daemon app, we usually use client credential flow to gain the access token/credential to call the api in the daemon so that we don't need to let user sign in and then call the api, this flow makes the app itself can call microsoft graph api. But using this flow will lead to the issue that you can't use me any more because you never signed in yourself, so we should use /users/userPrincipalName/calendars instead.
Then come to the programming module, microsoft provides graph SDK for calling api, this is what you can also see in the api document. You can refer to this document to learn more details about how to use client credential flow with graph SDK. You can also copy my code below.
using Azure.Identity;
using Microsoft.Graph;
public IActionResult Privacy()
{
var scopes = new[] { "https://graph.microsoft.com/.default" };
var tenantId = "your_tenant_name.onmicrosoft.com";
var clientId = "azure_ad_app_client_id";
var clientSecret = "client_secret";
var options = new TokenCredentialOptions
{
AuthorityHost = AzureAuthorityHosts.AzurePublicCloud
};
var clientSecretCredential = new ClientSecretCredential(
tenantId, clientId, clientSecret, options);
var graphClient = new GraphServiceClient(clientSecretCredential, scopes);
var res = graphClient.Users["your_user_id_which_looks_like_xxxx-xxx-xxx-xxxx-xxxxxx"].Calendars.Request().GetAsync().Result;
return View();
}
By the way, if you're not familiar with the flows, you may take a look at my this answer.
I was able to kind of resolve this issue after chatting with the Azure tech guy. It turned out that my Azure account was considered a personal account. And the reason for this apparently was because I was using a personal #yahoo.com email to setup up the Azure account first place. Because of this they would apparently not allow me to purchase o365 and license it. So I had to create a new account with the amazon default domain for S3 - awsapps.com, which I took from my AWS S3 subscription. Then I had to run through a whole process of creating a new email in Azure from my existing S3 custom domain.
After the email was created I was able to purchase o365 basic license (trial version for now) and then login to Azure using a new email. o365 purchase gave me access to outlook and then recreating a new daemon application from the quickstart with the new credentials just worked.
I don't know if it makes sense what I had done as it sounds awfully convoluted. But it seems to work in the end.
Related
I have an Azure Functions API which uses Azure Active Directory authentication. I can test locally and deployed using a browser and curl calls in a process of:
Get a code
Use the code to get a token
Pass the token to authenticate and get the function result.
I now want to call this API from my Blazor WASM app but I'm sure there must be a nice MSAL call to do all the authentication but I cannot find any documentation on what that might be.
Does anyone have a code snippet to illustrate what needs to happen?
Further Information
My Azure Functions App and Blazor WASM client are not part of the same project and are hosted on different sub-domains of Azure hypotheticalapi.azurewebsites.net and hypotheticalweb.azurewebsites.net.
The web client application registration has API Permissions for the API and the API has an application registration which exposes itself with the scope that the client app has permissions for.
Again, the API and Web app work individually. I just don't seem able to get them to talk.
I have been following the "ASP.NET Core Blazor WebAssembly additional security scenarios" documentation but after several attempts I keep coming back to the error:
Microsoft.JSInterop.JSException: invalid_grant: AADSTS65001:
The user or administrator has not consented to use the application with ID 'e40aabb0-8ed5-4833-b50d-ec7ca4e07996' named 'BallerinaBlazor5Wasm'.
Send an interactive authorization request for this user and resource.
Even though I have revoked/deleted the client's permissions on the API, it has never repeated asking for consent. Is there a way I should clear the consent I previously gave? No idea how I might do that.
This GitHub Issue appears to be relevant.
I was stuck for the last two weeks with the same error code in the same setting: Blazor WASM talking to an AAD secured Azure Functions app.
What appeared to be a problem in my case was the scopes that I was listing in the http request when contacting AAD identification provider endpoints. Almost all examples I came across use Microsoft Graph API. There, User.Read is the scope that is given as an example. My first though was that even when I am contacting my own API I have to include the User.Read scope in the request because I was reasoning that this scope is necessary to identify the user. However, this is not the case and the only scope that you have to list when you call the authorize and token endpoints is the one that you exposed under the "Expose an API blade" in your AAD app registration.
I am using the OAuth2 authorization code in my example and not the implicit grant. Make sure that in the manifest of your API registration you have set "accessTokenAcceptedVersion": 2 and not "accessTokenAcceptedVersion": null. The latter implies the use of implicit flow as far as I know.
The scope the I exposed in my API is Api.Read. You can expose more scopes if you need but the point is that you only ask for scopes that you exposed.
I also have both following options unticked (i.e. no implicit flow). However, I tried with selecting "ID token" and it still worked. Note that the "ID token" option is selected by default if you let the Azure Portal create your AAD app registration from your function app Authentication blade.
Blazor code
Program.cs
This code has to be added.
builder.Services.AddScoped<GraphAPIAuthorizationMessageHandler>();
builder.Services.AddHttpClient("{NAME}",
client => client.BaseAddress = new Uri("https://your-azure-functions-url.net"))
.AddHttpMessageHandler<GraphAPIAuthorizationMessageHandler>();
builder.Services.AddScoped(sp => sp.GetRequiredService<IHttpClientFactory>()
.CreateClient("{NAME}"));
builder.Services.AddMsalAuthentication(options =>
{
builder.Configuration.Bind("AzureAd", options.ProviderOptions.Authentication);
// NOTE: no "api://" when providing the scope
options.ProviderOptions.DefaultAccessTokenScopes.Add("{you API application id}/{api exposed scope}");
});
appsetting.json
"AzureAd": {
"Authority": "https://login.microsoftonline.com/{aad tenant id}",
"ClientId": "{application id of your blazor wasm app}",
"ValidateAuthority": true
}
GraphAPIAuthorizationMessageHandler.cs
Note that this class can have a different name. you'll then also reference a different name in Program.cs.
public class GraphAPIAuthorizationMessageHandler : AuthorizationMessageHandler
{
public GraphAPIAuthorizationMessageHandler(IAccessTokenProvider provider,
NavigationManager navigationManager)
: base(provider, navigationManager)
{
ConfigureHandler(
authorizedUrls: new[] { "https://your-azure-functions-url.net" },
// NOTE: here with "api://"
scopes: new[] { "api://{you API application id}/{api exposed scope}" });
}
}
I hope this works. If not, let me know.
At least you need to get the access token, then use the token to call the function api. In this case, if you want to get the token in only one step, you could use the client credential flow, MSAL sample here, follow every part on the left to complete the prerequisites.
The following are the approximate steps(for more details, you still need to follow the sample above):
1.Create a new App registration and add a client secret.
2.Instantiate the confidential client application with a client secret
app = ConfidentialClientApplicationBuilder.Create(config.ClientId)
.WithClientSecret(config.ClientSecret)
.WithAuthority(new Uri(config.Authority))
.Build();
3.Get the token
string[] scopes = new string[] { "<AppId URI of your function related AD App>/.default" };
result = await app.AcquireTokenForClient(scopes)
.ExecuteAsync();
4.Call the function API
httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
// Call the web API.
HttpResponseMessage response = await _httpClient.GetAsync(apiUri);
...
}
I am looking for a complete Step-by-step to accomplish the following objective. I have been looking around and trying many, many ways, but not one of them works.
Objective: using C# .net core code (in Azure Functions) connect to a shared mailbox of Office 365 to retrieve emails [with date filter] to do some processing, then move that email from Inbox into another folder (Processed). I want to use MailKit (or something similar
that is free and has MIT license) to retrieve, load and parse the emails.
What I have done, but of course, I can be way off…
In Azure Active Directory, I have created an App Registration
In API Permissions, I have added and granted (I am an admin) a lot of permissions (everything I guess may be related to this, from
Email, to IMAP, SMTP, POP, Application, User and a bunch of other permissions.
In Certificates & Secrets, I created a client secret and recorded the secret (Value)
From Overview, I recorded the Client ID, Tenant ID, etc.
Code (I tried several variation of this…)
string[] scopes = {"https://graph.microsoft.com/.default" }
/*
for scopes, I have also tried:
“https://graph.microsoft.com/IMAP.AccessAsUser.All”
“https://outlook.office.com/IMAP.AccessAsUser.All”
*/
var authority = authority + tenant;
/*
for authority, I have also tried:
“https://login.microsoftonline.com/“
“https://login.microsoftonline.com/common”
“https://login.microsoftonline.com/oauth2”, etc…
*/
var client = ConfidentialClientApplicationBuilder
.Create(clientID)
.WithClientSecret(secret)
.WithAuthority(new Uri(authority))
.Build();
/* Fails every time! */
CancellationToken cancellationToken = default;
var authResult = await app.AcquireTokenForClient(scopes)
.ExecuteAsync(cancellationToken);
/* MailKit to retrieve emails… */
/*
any step-by-step code using MailKit to
accomplish the Objective would be much appreciated.
*/
Firstly, you should not use this method to get the access token.
var client = ConfidentialClientApplicationBuilder
.Create(clientID)
.WithClientSecret(secret)
.WithAuthority(new Uri(authority))
.Build();
This method is using client credential flow which is not supported to use IMAP.AccessAsUser.All delegated permission.
This method mentioned by jstedfast is using Interactive provider. The interactive flow is used by mobile applications (Xamarin and UWP) and desktops applications to call Microsoft Graph.
So if configuring "http://localhost" as a Public client (mobile & desktop) redirect URI for your application doesn't work, I don't think you could implement it in the C# .net core Azure Function app. Azure Function app doesn't support login interactively within it. You can only use it in a console app.
But there are 2 workarounds which allow you to get the user access token for Microsoft Graph.
Implement Username/password provider to generate the client and access token. But it is using ROPC flow which is not recommended by Microsoft. See details on Warning tip.
Configure additional Login Params in App service to get the access token to call Microsoft Graph. Please refer to CONFIGURING AN APP SERVICE TO GET AN ACCESS TOKEN FOR AAD GRAPH API. The key point is changing the additionaloginparams to the following [“response_type=code id_token”, “resource=https://graph.microsoft.com”]. Related official document here.
I have a REST API which uses Azure ADD App registration to allow other apps to call it.
In the Azure Portal, I have registered it as an Enterprise Application and also registered the consumer applications and assigned them Roles appropriately.
The authentication and RBAC works fine.
But the use case that I am working on requires me to identify and log the incoming request calling application's name (The one seen in the portal as 'Display Name', when we view the list of users and groups for an enterprise Application).
As advised in the internet, I am using some Identity related API to read the claims from the request header.
var provider = claimsUser.FindFirst("http://schemas.microsoft.com/identity/claims/identityprovider").Value;
var sid = claimsUser.FindFirst(ClaimTypes.NameIdentifier).Value;
OR
var sid = claimsUser.FindFirst("stable_sid").Value;
But this gives me a GUID value which I couldn't map to any of the consumers of the Enterprise Application.
The clients are all registered in the Azure portal.
In the Portal, I can see the apps in the "Users and Groups" section for the Enterprise application, with their appropriate roles.
In terms of usage, before making the call, the clients generate a bearer token based on the certificate that they get from Azure. The make the call with the bearer token attached to the request header. This bearer token is validated against the Azure AD, in the filters set before every controller..
What I want is to get are the details about this client who has made the call.. As per some repliers, and, to which I agree, the Guid that I get as part of the previous call mentioned above is for the actual user and not the app itself which is making the call.
Can anyone throw some light into it.. some code snippet will be of real help..
I'm not sure what authentication flow you are using, but SID is generally for a user that's logged in, not an application. if your client applications are using client id and secret, the token it returns that you send to the api should include the app registration guid. https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-client-creds-grant-flow#access-control-lists . So the appid and iss should give you the guid of the app registration. using this, you can make a call to graph api, to identify the display name of the app registration. https://learn.microsoft.com/en-us/graph/api/application-get?view=graph-rest-1.0&tabs=http
If your app is a user login app, and you don't want to make a call to graph, the other option you could do as a workaround would be to create app roles and assign users to them but name the app roles with some convention that includes the app's display name. then the name could come through under roles claim.. https://learn.microsoft.com/en-us/azure/active-directory/develop/howto-add-app-roles-in-azure-ad-apps
those are some options.. but other than calling graph or kinda working around to inject the name into a different claim of the token I'm not sure of any other method to get the "app registration's display name"
I'm having a little trouble following how API Access delegate permissions work with azure active directory. I feel like i'm probably misunderstanding a key aspect of how AAD works.
Here is my set up
I have a Web Application let’s call it WebApp. I have created
an AAD for the Web Application and registered with a AAD App ID. Let’s
call it App ID A
I have a Web Api let’s call it ApiService. I have also created an AAD for it and registered with a AAD App ID. Let’s all it App ID B.
In AAD App ID A, I have updated the clicked on the API Access ->
Required Permissions -> Add (App ID B ; Web API) permissions
I’ve updated the manaifest in the AAD App ID B, to give consent to
knownClientApplications to include the client ID of the Web App
I’ve also enable oauth2AllowImplicitFlow to be true for both App’s
manifest.
What I’m trying to do is, A user signs into the web application sign. When it signs in, the user is able to acquire a token for the specific Web App App ID A. The user should be able to use that token and have access the Api Service with App ID B. I thought by configuring the whole API Access -> Required Permissions within the Web Application it would give me delegate permission with the logged in user to communicate with the Api Service WebApi.
When I examine the JWT token, I notice that there is a claim for Microsoft Graph, but not for the ApiService. Shouldn’t I be seeing a claim?
When I try to use the token, it reacts with a 404 authentication error.
Any advice appreciated,
Thanks,
Derek
UPDATE
In response to #joonasw
I actually looked at the example you wrote when i started.
https://joonasw.net/view/aspnet-core-2-azure-ad-authentication
In the example, the web application is initialized with:
.AddOpenIdConnect(opts =>
{
Configuration.GetSection("OpenIdConnect").Bind(opts);
opts.Events = new OpenIdConnectEvents
{
OnAuthorizationCodeReceived = ctx =>
{
return Task.CompletedTask;
}
};
});
In the HomeController, there is code to retrieve the token for the graph api
private async Task<string> GetAccessTokenAsync()
{
string authority = _authOptions.Authority;
string userId = User.FindFirstValue("http://schemas.microsoft.com/identity/claims/objectidentifier");
var cache = new AdalDistributedTokenCache(_cache, _dataProtectionProvider, userId);
var authContext = new AuthenticationContext(authority, cache);
//App's credentials may be needed if access tokens need to be refreshed with a refresh token
string clientId = _authOptions.ClientId;
string clientSecret = _authOptions.ClientSecret;
var credential = new ClientCredential(clientId, clientSecret);
var result = await authContext.AcquireTokenSilentAsync(
"https://graph.microsoft.com",
credential,
new UserIdentifier(userId, UserIdentifierType.UniqueId));
return result.AccessToken;
}
From my understanding, when the user initially login to the web application it will trigger the OnAuthorizationCodeReceived() method where it will be using the clientId/clientSecret/resource of the web applicaiton. The token is stored in the distributed token cache under the key resource/client id.
In the example, GetAccessTokenAsync() is used to grab the token to access the graph API.
In my case, I was hoping to update that method to retrieve the token for the WebApi which has a different clientId/clientSecret/resoruce. In my case, it will AcquireTokenSilentAsync will throw an AdalTokenAcquisitionExceptionFilter because the token needed is not stored in the cache and in the AdalTokenAcquisitionExceptionFilter it will call try to reauthenticate
context.Result = new ChallengeResult();
which will redirect to the authentication page and then hits the AddOpenIdConnect() method. However, the openIdConnect is configured with the web app clientID/ClientSecret/Resource and will not store the new token properly. It will try to call GetAccessTokenAsync() again and the whole process will go in an infinite loop.
In the example, if you were to comment out the "Anthentication:resource" in app.settings, you will experience the same issue with the infinite loop. What happens is that you initially authenticate correctly with no resource specified. Then when you click on you try to get the token for microsoft graph which is a new resource, it can't find it in the cache and then tries to reauthenticate over and over again.
I also notice that the acquireAsyncAuthentication only returns a AuthenticationResult with a bearer tokentype. How would you get the refresh token in this case?
Any advice?
Thanks,
Derek
UPDATE (Solution)
Thanks to #jaanus. All you have to do is update the resource to the clientid of the web api and pass that into AcquireTokenSilentAsync. The web api id uri that you can get from the azure portal did not work.
Okay, so it seems there are multiple questions here. I'll try to make some sense of this stuff to you.
Adding the "Web App"'s client id to the "ApiService" knownClientApplications is a good idea.
It allows for consent to be done for both apps at the same time. This really only matters for multi-tenant scenarios though.
Now, your Web App will be acquiring access tokens at some point.
When it does, it must specify a resource parameter.
This parameter says to AAD which API you wish to call.
In the case of the "ApiService", you should use either its client id or Application ID URI (this is more common).
Depending on the type of your Web App, the access token is acquired a bit differently.
For "traditional" back-end apps, the Authorization Code Grant flow is usually used.
In this flow your back-end gets an authorization code after the user logs in, and your Web App can then exchange that code for the access token.
In the case of a front-end JavaScript app, you would use the Implicit Grant flow, which you have allowed (no need to enable it in the API by the way).
This one allows you to get access tokens directly from the authorization endpoint (/oauth2/authorize) without talking to the token endpoint as you usually have to.
You can actually get the access token right away after login in the fragment of the URL if you wish.
ADAL.JS makes this quite a lot easier for you if you are going in this route.
The reason you get the authentication error is because the access token is probably meant for Microsoft Graph API. You need to request an access token for your API.
An access token is always only valid for one API.
The API is a backend to a mobile app. I don't need user authentication. I simply need a way to secure access to this API. Currently, my backend is exposed.
The documentation seems to only talk about user authentication and authorization, which is not what I need here. I just need to ensure only my mobile app can talk to this backend and no one else.
Yes, you can do that: use authentication to secure your endpoints without doing user authentication.
I have found that this way of doing it is not well documented, and I haven't actually done it myself, but I intend to so I paid attention when I saw it being discussed on some of the IO13 videos (I think that's where I saw it):
Here's my understanding of what's involved:
Create a Google API project (though this doesn't really involve their API's, other than authentication itself).
Create OATH client ID's that are tied to your app via its package name and the SHA1 fingerprint of the certificate that you will sign the app with.
You will add these client ID's to the list of acceptable ID's for your endpoints. You will add the User parameter to your endpoints, but it will be null since no user is specified.
#ApiMethod(
name = "sendInfo",
clientIds = { Config.WEB_CLIENT_ID, Config.MY_APP_CLIENT_ID, Config.MY_DEBUG_CLIENT_ID },
audiences = { Config.WEB_CLIENT_ID }
// Yes, you specify a 'web' ID even if this isn't a Web client.
)
public void sendInfo(User user, Info greeting) {
There is some decent documentation about the above, here:
https://developers.google.com/appengine/docs/java/endpoints/auth
Your client app will specify these client ID's when formulating the endpoint service call. All the OATH details will get taken care of behind the scenes on your client device such that your client ID's are translated into authentication tokens.
HttpTransport transport = AndroidHttp.newCompatibleTransport();
JsonFactory jsonFactory = new JacksonFactory();
GoogleAccountCredential credential = GoogleAccountCredential.usingAudience( ctx, Config.WEB_CLIENT_ID );
//credential.setSelectedAccountName( user ); // not specify a user
Myendpoint.Builder builder = new Myendpoint.Builder( transport, jsonFactory, credential );
This client code is just my best guess - sorry. If anyone else has a reference for exactly what the client code should look like then I too would be interested.
I'm sorry to say that Google doesn't provide a solution for your problem (which is my problem too).
You can use their API key mechanism (see https://developers.google.com/console/help/new/#usingkeys), but there is a huge hole in this strategy courtesy of Google's own API explorer (see https://developers.google.com/apis-explorer/#p/), which is a great development tool to test API's, but exposes all Cloud Endpoint API's, not just Google's services API's. This means anyone with the name of your project can browse and call your API at their leisure since the API explorer circumvents the API key security.
I found a workaround (based on bossylobster's great response to this post: Simple Access API (Developer Key) with Google Cloud Endpoint (Python) ), which is to pass a request field that is not part of the message request definition in your client API, and then read it in your API server. If you don't find the undocumented field, you raise an unauthorized exception. This will plug the hole created by the API explorer.
In iOS (which I'm using for my app), you add a property to each request class (the ones created by Google's API generator tool) like so:
#property (copy) NSString *hiddenProperty;
and set its value to a key that you choose. In your server code (python in my case) you check for its existence and barf if you don't see it or its not set to the value that your server and client will agree on:
mykey,keytype = request.get_unrecognized_field_info('hiddenProperty')
if mykey != 'my_supersecret_key':
raise endpoints.UnauthorizedException('No, you dont!')
Hope this puts you on the right track
The documentation is only for the client. What I need is documentation
on how to provide Service Account functionality on the server side.
This could mean a couple of different things, but I'd like to address what I think the question is asking. If you only want your service account to access your service, then you can just add the service account's clientId to your #Api/#ApiMethod annotations, build a GoogleCredential, and invoke your service as you normally would. Specifically...
In the google developer's console, create a new service account. This will create a .p12 file which is automatically downloaded. This is used by the client in the documentation you linked to. If you can't keep the .p12 secure, then this isn't much more secure than a password. I'm guessing that's why this isn't explicitly laid out in the Cloud Endpoints documentation.
You add the CLIENT ID displayed in the google developer's console to the clientIds in your #Api or #ApiMethod annotation
import com.google.appengine.api.users.User
#ApiMethod(name = "doIt", scopes = { Constants.EMAIL_SCOPE },
clientIds = { "12345678901-12acg1ez8lf51spfl06lznd1dsasdfj.apps.googleusercontent.com" })
public void doIt(User user){ //by convention, add User parameter to existing params
// if no client id is passed or the oauth2 token doesn't
// match your clientId then user will be null and the dev server
// will print a warning message like this:
// WARNING: getCurrentUser: clientId 1234654321.apps.googleusercontent.com not allowed
//..
}
You build a client the same way you would with the unsecured version, the only difference being you create a GoogleCredential object to pass to your service's MyService.Builder.
HttpTransport httpTransport = new NetHttpTransport(); // or build AndroidHttpClient on Android however you wish
JsonFactory jsonFactory = new JacksonFactory();
// assuming you put the .p12 for your service acccount
// (from the developer's console) on the classpath;
// when you deploy you'll have to figure out where you are really
// going to put this and load it in the appropriate manner
URL url = getClass().class.getResource("/YOURAPP-b12345677654.p12");
File p12file = new File(url.toURI());
GoogleCredential.Builder credentialBuilder = new GoogleCredential.Builder();
credentialBuilder.setTransport(httpTransport);
credentialBuilder.setJsonFactory(jsonFactory);
//NOTE: use service account EMAIL (not client id)
credentialBuilder.setServiceAccountId("12345678901-12acg1ez8lf51spfl06lznd1dsasdfj#developer.gserviceaccount.com"); credentialBuilder.setServiceAccountScopes(Collections.singleton("https://www.googleapis.com/auth/userinfo.email"));
credentialBuilder.setServiceAccountPrivateKeyFromP12File(p12file);
GoogleCredential credential = credentialBuilder.build();
Now invoke your generated client the same way
you would the unsecured version, except the builder takes
our google credential from above as the last argument
MyService.Builder builder = new MyService.Builder(httpTransport, jsonFactory, credential);
builder.setApplicationName("APP NAME");
builder.setRootUrl("http://localhost:8080/_ah/api");
final MyService service = builder.build();
// invoke service same as unsecured version