Building Daemon or Service Apps with Office 365 Mail, Calendar, and Contacts APIs (OAuth2 client credential flow)


Device and Web Server applications usually require a user to sign-on and consent to allow the application to access and work with their information in Office 365. The underlying protocol to gain access is based on the OAuth2 authorization code grant flow. I described this a while ago in one of my earlier blogs Using OAuth2 to access Calendar, Contact and Mail API in Office 365 Exchange Online. As part of this OAuth2 flow, the application gets an access token/refresh token pair that represents a delegation given to the application by a specific individual user for a set of permissions. Essentially before the application can access data for a user, it has to get an access token/refresh token for each user, and to get those the user has to sign-on to the application at least once.

 

There are however a category of applications where this is not desirable or possible. These applications usually run in the background as a daemon app or service and need access without the user having to sign-on. OAuth2 provides a different flow for these types of applications, called the client credential grant flow. You can read more about this flow in the AAD Authentication Protocol documentation here. We’re happy to announce that Office 365 now supports this flow to gain access to the Office 365 Calendar, Contacts and Mail APIs.

 

When using this flow, the application presents its client credentials to the OAuth2 token issuing endpoint, and in return gets an access token that represents the application itself without any user information. This is sometime also called an “App-Only” token. There is no need for the application to get a refresh token. When the access token expires, it simply goes back to the OAuth2 token issuing endpoint to get a new one. Also, since there is no user information in the token, the app must specify the user within the API call when using this “App-Only” token.

 

Note: Access token lifetime is currently 60 minutes. This applies to all access tokens in Office 365, regardless which OAuth2 flow is used.

 

 

Defining permissions

 

The first step to configure your application to use “App-Only” tokens is to define what permissions your application needs. Just like permissions for authorization code grant flow apps, these permissions are defined with the application registration in the Microsoft Azure Management Portal for Azure Active Directory (AAD). While the permissions for the authorization code grant flow are called “Delegated Permissions” (because a user delegates those permission to the app), the permissions for the client credential flow are called “Application permissions” (because those permissions are directly assigned to the application).

 

Below is a screen shot of the AAD Application Registration permissions section:

Machine generated alternative text:<br />
permissions to other applications<br />
Delegated Permissions: 1<br />
Delegated Permissions: O<br />
Windows Azure Active Directory<br />
Office 365 Exchange Online<br />
Add application<br />
Application Permissions: 1<br />
Application Permissions: 3

 

Note: When creating the application, the application must be created as a “Web Application and/or Web API” within the AAD application management portal.

 

 

Granting consent and app authentication strength

 

Now that application permissions are defined within the application registration, the application can ask for consent to be available in another Office 365 organization. Application Permissions must be consented by a tenant administrator (global administrator) of an Office 365 organization. This is because these applications are quite powerful in terms of what data they can access in the Office 365 organization. For example, a service application with the Mail.Read permission that acquires access tokens via client credential flow can read mail in any mailbox in the Office 365 organization.

 

Because of the broad access these kinds of apps enjoy, there is an additional requirement for the app to successfully obtain an access token. Instead of using a client ID and client secret, the app must use an X.509 certificate with a public/private key pair. Usage of simple symmetric keys are not allowed, and while the application could get an access token using a symmetric key, the API will return an access denied error with such an access token. Self-issued X.509 certificates are accepted, but the application must register the public X.509 certificate in AAD with the application definition. The app then maintains the private key and uses it to assert its identity to the token issuing endpoint.

 

The application implements the consent flow in a similar way as the authorization code grant flow by sending a request to the OAuth2 authorize endpoint. However when the authorize endpoint redirects back with an authorization code to the application, the code can be happily ignored and thrown away. For getting tokens only the client credentials are necessary. Most applications build an experience such as “Sign-up my Organization” to accomplish the initial one-time consent.

 

The key take away of this section is that one-time consent is part of a daemon app configuration.  Once the consent is given, the service or daemon app can get access tokens and start calling the Office 365 Rest APIs.

 

 

Revoking consent

 

Consent to service applications can be revoked just like for other applications that are installed by a tenant administrator of the Office 365 organization. The administrator can either go to the AAD Azure Management Portal, find the application in the application view, select and delete it, or alternatively the administrator can use Azure AD PowerShell to remove the app via the “Remove-MSOLServicePrincipalcmdlet.

 

 

Acquiring an access token with client credential flow

 

There is one important aspect when asking for app-only tokens: a tenant specific token issuing endpoint must be used. In other words, the “common” OAuth2 token issuing endpoint https://login.windows.net/common/oauth2/token cannot be used in this flow and will return an error.

 

The application can get the tenant specific endpoint quite easily. During the consent, when the authorize endpoint is hit and a code is delivered in the redirect to the application, an ID token can be requested together with the code. This ID token contains the tenant Id as “tid” claim-type. As the ID token is a JSON Web Token it is fairly simple to parse.

 

Getting an Initial ID token with Consent

 

Below is an example of how to trigger consent using an OpenID Connect Hybrid Flow (see OpenID spec here) request. This request will provide your application with the consent flow and redirect back with the code and ID token in a post request. Your application can ignore the code and get the ID token from the received form data (see OpenID spec on form post response mode)

 

GET https://login.windows.net/common/oauth2/authorize?state=e82ea723-7112-472c-94d4-6e66c0ca52b6&response_type=code+id_token&scope=openid&nonce=c328d2df-43d1-4e4d-a884-7cfb492beadc&client_id=0308CDD9-874D-4F87-85E0-A0DA7E05F999&redirect_uri=https:%2f%2flocalhost:44304%2fHome%2f&resource=https:%2f%2fgraph.ppe.windows.net%2f&prompt=admin_consent&response_mode=form_post HTTP/1.1

 

In ASP.Net you could simply retrieve the ID token via Request.Form[id_token“] on your redirect page.  You can find the tenantId in the “tid” claim within the JWT id_token.

 

 

 

In the example below I used Azure Active Directory Client library (ADAL) to acquire an “app-only” access token via client credential flow. My application maintains the private key in a well-protected directory on my web server as a PFX file. However it is better to maintain key material in a more secure storage such as the Windows certificate storage of the computer account.

 

Code snippet: Getting an “App-Only” token

 

           // need to address the tenant specific authority/token issuing endpoint

          //  https://login.windows.net/<tenant-id>/oauth2/authorize

          //  retrieved tenantID from ID token for the app during consent flow (authorize flow)

    string authority = appConfig.AuthorizationUri.Replace(“common”, tenantId);

               AuthenticationContext authenticationContext = new AuthenticationContext(

                   authority,

                   false);

 

               string certfile = Server.MapPath(appConfig.ClientCertificatePfx);

 

                X509Certificate2 cert = new X509Certificate2(

                    certfile,

                    appConfig.ClientCertificatePfxPassword, // password for the cert file containing private key

                    X509KeyStorageFlags.MachineKeySet);

 

                ClientAssertionCertificate cac = new ClientAssertionCertificate(

                    appConfig.ClientId, cert);

                   

                var authenticationResult = await authenticationContext.AcquireTokenAsync(

                    resource,   // always https://outlook.office365.com for Mail, Calendar, Contacts API

                    cac);

 

                return authenticationResult.AccessToken;

 

 

Note: The complete sample of a web app using client credential flow is available in GitHub on

·        https://github.com/mattleib/o365api-as-apponly-webapp

 

 

 

Configuring a X.509 public cert for your application

 

One last challenge is how to actually configure a X.509 public certificate with the application definition. Unfortunately X.509 certificates are not exposed as a UI element in the AAD application management portal. The applications public certificates need to be managed through the manifest.

 

Step 0: (If you do not have an X.509 certificate already) Create a self-issued certificate

You can easily generate a self-issued certificate with the makecert.exe tool.

 

1.      From the command line, run: makecert -r –pe -n “CN=MyCompanyName MyAppName Cert” -b 12/15/2014 -e 12/15/2016 –ss my –len 2048

2.      Open the Certificates MMC snap-in and connect to your user account. Find the new certificate in the Personal folder and export it to a base64-encoded CER file.

 

Note: Make sure the key length is at least 2048 when generating the X.509 certificate. Shorter key length are not accepted as valid keys.

 

 

Step 1:  Get the base64 encoded cert value and thumbprint from a .cer X509 public cert file using PowerShell

 

Note: The instructions below show using Windows PowerShell to get properties of a x.509 certificate. Other platforms provide similar tools to retrieve properties of certificates.

 

$cer = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2

$cer.Import(“mycer.cer”)

$bin = $cer.GetRawCertData()

$base64Value = [System.Convert]::ToBase64String($bin)

 

$bin = $cer.GetCertHash()

$base64Thumbprint = [System.Convert]::ToBase64String($bin)

 

$keyid = [System.Guid]::NewGuid().ToString()

 

Store the values for $base64Thumbprint, $base64Value and $keyid, to be used in the next step.

Step 2:  Upload cert through the manifest file

 

3.      Log in to the Azure Management Portal (https://manage.windowsazure.com)

4.      Go to the AAD snap-in and there navigate to the application that you want to configure with an X.509 certificate

5.      Download the application manifest file through the Azure Management Portal

Machine generated alternative text:<br />
VIEW<br />
Manifest<br />
MANAGE<br />
MANIFEST<br />
UPLOAD Lca

 

6.      Replace the empty KeyCredentials”: [], property with the following JSON.  NOTE:  The KeyCredentials complex type is documented here:  http://msdn.microsoft.com/en-us/library/azure/dn151681.aspx

 

  “keyCredentials“: [

    {

      “customKeyIdentifier“: “$base64Thumbprint_from_above”,

      “keyId“: “$keyid_from_above“,

      “type”: “AsymmetricX509Cert”,

      “usage”: “Verify”,

      “value”:  “$base64Value_from_above”

     }

   ],

 

e.g.

 

  keyCredentials“: [

    {

      customKeyIdentifier“: “ieF43L8nkyw/PEHjWvj+PkWebXk=”,

      keyId“: “2d6d849e-3e9e-46cd-b5ed-0f9e30d078cc”,

      “type”: “AsymmetricX509Cert”,

      “usage”: “Verify”,

      “value”: “MIICWjCCAgSgAwIBA***omitted for brevity***qoD4dmgJqZmXDfFyQ”

    }

  ],

 

7.      Save the change to the application manifest file.

8.      Upload the edited application manifest file through the Azure Management Portal.

9.      Optional:  Download the manifest again, and see your X.509 cert is present on the application.

 

Note:  KeyCredentials is a collection, so it’s totally possible to upload multiple X.509 certificates for rollover scenarios, or delete certs for compromise scenarios.

 

 

Must-Do Application Developing practices calling Mail, Calendar and Contacts API

 

Unrelated to OAuth2, there are three HTTP request headers you should always include when making requests to the Office365 APIs. This is the “User-Agent” the “client-request-id” and “Date”. For User-Agent you can follow RFC 2616 which basically describes it as {ProductName}/{ProductVersion} [{comment}]. For “client-request-id” your app should create a new GUID for each request. When the request fails “return-client-request-id” returns the GUID that was submitted as “client-request-id” with the request. It is highly recommended that you persist the failed request together with client-request-id and all HTTP response headers in some application log. The “Date” request header signals the date and time that the message was sent. It should follow the “HTTP-date” format as defined by RFC 2616)}. If you ever need help troubleshooting your application with the Office 365 APIs, this will be pave the route to a fast and successful resolution of the problem.

 

 

Summary

 

To sum up:

·        With the availability of the OAuth2 client credential flow it is now possible to build daemon or service apps in addition to device and web server applications. 

·        The installation or bootstrapping of those service apps is very similar to web server apps and requires an administrator of an Office 365 organization to consent.

·        Unlike web server apps, which can use symmetric keys, a service app must use X.509 certificates as authentication strength to acquire access tokens and successfully call the Mail, Calendar and Contacts APIs.

·        Service apps have the requested access level to all mailboxes in the Office 365 organization the administrator has consented to.

·        Service apps can be revoked by an administrator of the Office 365 organization in the same way like web server apps.

 

As always, thank you for reading and feedback, questions, etc. are very much appreciated!

 

Please use Stack Overflow for questions, and be sure to tag your post with “office365”.

 

Matthias Leibmann

 

 

References

OAuth2 client credential flow: http://msdn.microsoft.com/en-us/library/azure/dn645543.aspx

OAuth2 client libraries: http://msdn.microsoft.com/en-us/library/azure/dn151135.aspx

AAD on GitHubhttps://github.com/AzureADSamples

OAuth Sandbox: https://oauthplay.azurewebsites.net/

API Sandbox: http://apisandbox.msdn.microsoft.com/

Platform Overview: http://msdn.microsoft.com/en-us/office/office365/howto/platform-development-overview

Apps for Office: http://msdn.microsoft.com/en-us/library/office/fp161507(v=office.15).aspx

Office on Github: https://github.com/OfficeDev

Sample Web App to this Bloghttps://github.com/mattleib/o365api-as-apponly-webapp

 

 

Comments (90)

  1. Pranjal says:

    Hi Matthias,

    I have asked a question on Stack Overflow

    stackoverflow.com/…/building-daemon-or-service-apps-with-office-365-mail-throwing-401-error-code

    Can you please suggest?

  2. Nick says:

    Hi Matthias and Team,

    I am having issues with the asymmetric key authentication. I'm using Ruby so its hard to follow the examples. However I have created a Stack Overflow question here: stackoverflow.com/…/office-365-rest-api-daemon-week-authentication

    Thanks, Nick.

  3. My colleague Jason Johnston and I provided some answers/insights on the stackoverflow.com/…/office-365-rest-api-daemon-week-authentication. Please also note after you are over the hurdle of getting the access token, if you get any 401 errors when hitting the Calendar, Contacts and Rest APIs to look at the x-ms-diagnostics http response header.

  4. Robert says:

    It'd be great to have a sample console application that does something simple like listing the messages of a particular user's inbox. I've tried for a while now to get something running to no avail. For a while I was getting Unauthorized exceptions, but then finally got to a point with an access token and now get "Access is denied." exceptions.

  5. @Robert: you mean a console app that uses Rest API or EWS API and the described app-only flow or different flow? Let me know. I will see what I can do.

  6. Pranjal says:

    Hi Matthias,

    Everything worked fine for me! It worked and I was able to fetch calendar and mail data, but now suddenly it has started throwing me an error:

    Caused by: com.microsoft.aad.adal4j.AuthenticationException: {"error_description":"AADSTS70002: Error validating credentials. AADSTS50064: Credential validation failed.rnTrace ID: 4d47209b-de38-4bfe-849e-4f999bd6d374rnCorrelation ID: 78e90f01-01f8-4c71-956f-18528061e05brnTimestamp: 2015-02-09 08:27:05Z","error":"unauthorized_client"}

    I have asked question on stack overflow related to this on link:

    stackoverflow.com/…/building-daemon-or-service-apps-with-office-365-mail-throwing-aadsts70002-error.

    Can you please suggest?

  7. Robert says:

    @Matthias, I've been attempting to use the SDK (which I assume uses the REST API behind the scenes). I'm getting an access token and an OutlookServicesClient, but then fail with authentication issues when I try to…

    IPagedCollection<IMessage> messagesResults = await client.Users.GetById("the-user-guid").Messages.ExecuteAsync();

    Yes, app-only flow (i.e. a service or scheduled console app that runs with no user interaction to perform management functions).

    An example of this flow would be amazing and much appreciated! I have a feeling I'm like 95% there, but missing something.

  8. Robert says:

    @Matthias, I have a feeling that 1 thing I'm missing is the "initial one-time consent". Although I'm currently getting an access token, I haven't done any OAuth flow to do a one-time consent. Maybe that's what I'm missing.

  9. Robert says:

    @Matthias, for what it's worth, I got a working example now using some code based off your "o365api-as-apponly-webapp" example. That example doesn't use the SDK calls but rather HttpClient, so I'm not sure where the breakdown is.

  10. Kelly says:

    Would this daemon/service app work for native mobile apps ? Or would I have to build a web api to get the data I need then access this through my native app?

  11. @Robert:

    It should be possible to use the Office 365 SDK. E.g. something like below:

    OutlookServicesClient exClient = new OutlookServicesClient(dcr.ServiceEndpointUri,

    async () =>

    {

    var authResult = await authContext.AcquireTokenAsyn(……);

    return authResult.AccessToken;

    });

    So, in theory, you should be able to get the app only access token in the delegate. Wrapping this in the delegate means that the code will be executed only when the Outlook client needs.

    And yes, you need to consent if your app want to access resources in other tenants. When you create your application in a tenant it automatically has the permissions granted for the tenant it is registered, but no other other tenant. For your app to work in other tenants, it requires that an admin in a tenant consents to the permissions. This will "install" under the cover your app (technically correct would be to create a app principal for your app with those permission in the consented tenant).

    So you are indeed probably very close getting this all working with the SDK πŸ™‚

    @Kelly:

    Yes, indeed the correct way would be to create a Web API (service) for your device app. You then protect your Web API by for example integrating it with AAD (many examples there on github, e.g. github.com/…/NativeClient-WebAPI-MultiTenant-WindowsStore). Your Web API then would get an App-Only token to do the work, and you would never expose the App Token to the device app.

  12. Srabon says:

    @Robert, how did you do this (  "initial one-time consent" ) in your client console application ?

  13. priya says:

    hi Mathias

            I am trying to get an Initial ID token with Consent . The admin signs in and after that i get a response with error as  the resource is invalid the Resource+%27http%3a%2f%2foffice.microsoft.com%2foutlook%2f%27+is+not+registered+for+the+account. What does this mean ??? where am i going wrong ???

  14. Eric says:

    @Pranjal : I'm facing the same issue as you mentionned.

    Did you managed to retrieve a token ?

    I could not find your stackoverflow question as it was probably removed, but I opened one for my issue here if anyone want have a look ?

    stackoverflow.com/…/active-directory-authentication-for-java-application-with-oauth2-client-credenti

    Thanks a lot.

  15. Eric says:

    @Srabon : I may have missed that part too ( "initial one-time consent" ) as I could only understand that this part was refering to the configuration of the application in the Azure AD management.

    Could you confirm if it needs any other operation ?

    Thanks

  16. Eric says:

    I finally managed to retrieve an access token by upgrading my common-codecs artifact from 1.4 (with which it was not working) to 1.10 (took the last one available, but don't know from which version the correction was made).

    We got thinking of the common-codecs artifact because the JWT token presented had a public certificate value with "rn" inserted when generated by my app, whereas it hadn't when it was generated from a dedicated sample test app.

    Those "rn" characters were inserted into the "x5c" JWT header property by a call to  org.apache.commons.codec.binary.Base64.encodeBase64String(byte[]) from com.microsoft.aad.adal4j.AsymmetricKeyCredential.getPublicCertificate().

    It appeared that my app had already a depency to common-codecs v1.4 which didn't suit to adal4j.

  17. @priya: The resource to specify is "outlook.office365.com/". The error message means that the resource that is specified in the request is not registered in the auth server (AAD), which is correct as "office.microsoft.com/outlook" is not registered on our application object for Exchange Online.

  18. @Robert/Srabon/Eric: I don't think you can trigger admin consent in a console app, though I never tried it. Though as you don't care about the redirect you can probably bootstrap a console app by simply calling the authorize endpoint and assume the consent happened. Then in your console app if the token request fails with an unauthorized error indicating consent is missing, you can surface this in some way to the system (e.g. logs, eventlogs, alerts). Probably better is to have some kind of "install the app" experience that is triggered at time when the app is acquired. It all depends on the scenario. E.g. if the app can be categorized as a "LOB app" that each organization acquires and installs separately you can also envision that a different AppID is created with a different key for each individual organization. But this would be a compete different route than treating it as a "multi-tenant" app (using the same AppID for all organizations signing-up for the service) with a different experience (a setup) you would have to build. I would have to look into possibilities if this can be for example automated via powershell tasks. Again, this would mean you build some kind of a setup one has to run before using the app, vs. leveraging the consent model that allows your app being made available in an organization by means of a sign-up experience via a web driven authorization flow.

  19. @Eric. Thank you for figuring this out and positively closing the loop with us! I'll let the developers know that this was the issue to stop pulling their hairs what's going on πŸ™‚

  20. Archana says:

    Hi Matthias

         I followed your steps to create a certificate and uploaded the manifest file  . It was successfully uploaded . when i try to download the file again and view i find the value field as null . Is it a mistake on my side ?

  21. Eric says:

    @Archana : no I'm in this case too, but though this is quite disturbing, don't bother with it, it doesn't matter.

  22. Steve says:

    In that case building the service apps look like a good idea.

  23. Randor says:

    Is is possible to get a walkthrough or example on how to utilise this method with PHP? I'm struggling to utilise this method with PHP.

  24. Alexis says:

    I need help to implement on an apps php. Can you give me some help please ?

  25. Check out the git of my colleague Jason Johnston with a php example accessing calendar: github.com/…/php-calendar. While this is not client credential flow, it implements the code flow which probably is what you want for a regular user based web app.

  26. A brief note on EWS access as I did not mention this in great detail in my blog: EWS access is supported with app only in following way: 1. Configure the app for "Full Access to users mailbox" application permission – in the App Token this is "full_access_as_app". 2. Set the EWS impersonation header. 3. Set the "X-AnchorMailbox" http request header to the mailbox you like to access.

  27. Alexis says:

    thanks for this information. But i want to implement client credential flow with Php. Can you help me please?

  28. Randor says:

    I would also be interested in some help regarding implementing this credential flow via PHP. The problem I'm having is that the library you are using (ADAL) has no PHP equivalent that I am aware of, and am thus unsure how anything is working within that library.

    Even a breakdown of what is going on during those library calls, what requests are made (with what data, and their responses) would be incredibly useful. I have the certificate, etc, but no idea what to do with it. Cheers!

  29. While we don't have a php example, we do have a .net and python example. Checkout the .net one in my git on github.com/…/o365api-as-apponly-webapp and the python one on github.com/…/python_clientcred.  Both show you how to craft the payload and make the token request without the ADAL library and how to parse the response.

    1. Rico Geromo says:

      Hello Matthias, can you build an using PHP? I hope you can. Thank you

    2. Rico Geromo says:

      I have a project that I think the appropriate approach is daemon because it need to process without human intervention. I hope you can give an example using PHP. Thanks

  30. Randor says:

    Thanks so much for the links, extremely helpful examples!

  31. Igor says:

    Is it possible to use app only token to query "Discovery Service REST API"? It doesn't seem to work giving "access denied" error.

  32. Mick Badran says:

    Hi guys – great example however I've hit a brick wall.

    (this is my first experiment into O365 Rest APIs – so there could be glaringly obvious things I'm missing)

    I was redirected to this page from this code sample – dev.office.com/…/2143

    I get a token successfully – but when calling the Exchange APIs I get 'Forbidden' error.

    I've rechecked all my settings, certs, keys etc. (3 different O365 environments)

    Has anyone got this sample working?

    Cheers,

    Mick.

  33. Mick Badran says:

    I've narrowed down the call to

    https://graph.microsoft.com

    {"odata.error":{"code":"Authorization_RequestDenied","message":{"lang":"en","value":"Insufficient privileges to complete the operation."}}}

  34. Mick,

    Add the "Read directory data" under applications permissions for Windows Azure Active Directory. This was missing from the registration instructions. Matthias added it this morning. See step 12 here: github.com/…/o365api-as-apponly-webapp.

    Jason

  35. Mick Badran says:

    Thanks Jason & Matthias – woks like a treat now!

    One thing puzzles me in this sample – I supply the Admin user/pass for the one-off authorization, but this happens each time I launch the app.

    Is this just because of the App and it's not saving the fact it's been already registered for that tenant?

    Great example – now slice and dice it.

  36. Wei Shao says:

    HI Matthias,

    Is (OneDrive) File API supported in this style?

    stackoverflow.com/…/access-all-domain-users-file-in-offie365-onedrive

    Thanks,

    Wei

  37. Jake says:

    Since there's no user context via OAuth client credential flow, how would one use the Discovery API with an access token? msdn.microsoft.com/…/discovery-service-rest-operations requires a `/me` context.

  38. Mark Nelson says:

    I have created a PHP example on how to implement the office365 OAuth2 client credential flow.

    github.com/…/php_office365_cleintcred

  39. Very nice Mark! Thank you for doing this and sharing!

  40. @Jake and Igor: You are correct. App-Only does not work for Discovery.

    @Wei, yes we recently added App-Only support of OneDrive for Business. Let me try to find out some more information for you on this.

  41. Harish Patel says:

    Please anyone can tell how to use x.509 in php or calling office 365 API.

  42. Andrew Pitts says:

    It would be great to see an openSSL alternative to makeCert + Powershell….for all the Linux dev's out there.  I just spent much longer than I care to admit getting makeCert and Powershell up and running on a VM.

  43. Mark Nelson says:

    You can generate an x.509 certificate using openSSL. Then you need to generate the fingerprint and the key id. The last step is extracting the private key. You don't need to do it using windows key manager. OpenSSL can do all of those things for you. Here is a link that should have all the OpenSSL commands you will need. redkestrel.co.uk/…/openssl-commands

    Just read the tutorial above and make sure you are generating it using the correct requirements listed.

  44. James Zou says:

    Hi Matthias et al,

    I also want to know if this access token mechanism work with the OneDrive for business?

    From my understanding behind the OneDrive for business are sharepoint servers,  so theoretically the Sharepoint API should also work with  OneDrive for business,  as I know in Sharepoint API, there is SPUserToken method to do the Impersonate to other users, can you confirm if this method work with OneDrive for Business?

    Any more information about the OneDrive for business or some samples will be really helpful.

    Thanks in advance.

    James

  45. Dmytro Panfylov says:

    what is the point to set "X-AnchorMailbox" header?

  46. The "X-AnchorMailbox" is a routing hint for our front end servers to which backend to route the request for processing. You specify the e-mail address of the mailbox you want to get data from, and then our front ends lookup where the current active mailbox server is and deliver the request to this server.

    Hope this helps,

    Matthias

  47. Ree Shawn says:

    Blocked by the following two errors during Compilation of GIT Sample Project, can you let me know which step I missed?

    Could not copy the file "AccessMailboxAsAppContentmyappcert.pfx" because it was not found.

    Could not copy the file "AccessMailboxAsAppContentencryptionCert.pfx" because it was not found.

  48. Ree Shawn says:

    Hello Matthias,

    For the GITHub Sampel Project, I just asked a question on Stack Overflow, could you please suggest?

    stackoverflow.com/…/building-daemon-or-service-apps-with-office-365-mail-compilation-error

  49. Dmytro Panfylov says:

    Hi Matthias, is there any examples how to do queries to sharepoit using app only token?

  50. Ree Shawn says:

    Hello Matthias,

    The project is up&running now, thanks to help of Jason.

    Yet I ran into another problem, could you please suggest?

    stackoverflow.com/…/building-daemon-or-service-apps-with-office-365-that-doesnt-require-sign-in

  51. @Dmytro. I am still trying to find out what the exact plan is on App tokens for SharePoint. Can you actually send me e-mail to mattleib@microsoft.com, so I can include some people from SharePoint team.

  52. @Ree: I saw that Jason already helped you there. Thank you Jason for being on the ball! πŸ™‚

  53. Mix Kira says:

    I Matthias, and thanks for this post πŸ™‚

    I'm creating a task in php that should access the onedrive for business of some of my user.

    I've downloaded the php example that have assertion in it, and the assertion with the certificate work, calling the token endpoint.

    But I need to make also the authorization (I've called and other api, with the barrer header, but it give me back a 401, so probably I'm missing the authorization)

    Since the application is a sort of daemon (I don't execute it throught the web browser) I could not authorize logging in the administrator.

    I've tried to call the login.windows.net/…/authorize endpoint, instead of token endpoint, with the assertion (that work with token endpoint), like I see in the c# project example in this page, but the api return me an html with the login page, instead of a json like I expect.

    I'm I missing something?

    I would also ask some other question about the authorization mechanism for the app-only (I haven't found too much information about it):

    -Does the application need to be "authorized" from an administrator, logging in it, or the certificate is enought to authenticate it?

    -If there's the needing for the authorization, can be done only throught a form online, or maybe with a rest call and some parameter?

    -How often does the application need the authorization? Every time I request a new token? Only once from when the AAD app is created?

    -What's the difference between use the client_secret and the certificate, calling the token api?

    I've worked with the google apps oauth2 api, and they only need the client_id and p12 certificate to assert and authenticate the call.

    Thanks for the help

    Best regards

  54. Mix Kira says:

    Hi Matthias,

    I've worked on the problem a bit and I've some new results:

    For the authorize, I found that passing my admin email through login_hint parameter, it work, and gave me a "HTTP/1.1 100 Continue", that I think is an Ok, you're authorized..

    Now, calling the api, I have a http 500 error, as I described here:

    stackoverflow.com/…/office-365-unified-api-object-reference-not-set-to-an-instance-of-an-object

    But, after a day of try, I've a question: Does the new unified api work with this authentication workflow? Or only the "exchange" api works?

    I've tried with the old sharepoint api, and they return to me that app-only token is not supported.. So, how can I create a daemon that access the user files?

    If you can answer, I would really appreciate (even on stackoverflow), because I need to decide if I need to change platform and don't use office 365.

    Thanks

  55. Hi Kira, sorry for the delayed response and thank you for working through this. First some brief things:

    1. The Unified API does not support yet App Tokens

    2. OneDrive also does not support App Tokens yet – both #1 and #2 is in the plans, but no solid ETA I could refer to. If this changes I will let the blog audience know as soon as I do

    3. login_hint should not be required to make consent work

    4. you only need to authorize the application once – you authorize against the authorize endpoint. Make sure you configured your app as multi-tenant app, so authorization works for all tenants.

    5. To authorize, an admin of the tenant need to provide consent via a standard OAuth2 authorize flow. No secret and cert is required there

    6. The result of #4 should be that your app knows that a tenant signed-up and maintains this information

    7. after successful #4, your app never goes back to the authorize endpoint, but always gets new access tokens by calling the token issuing endpoint for a signed-up tenant. For this you need to assert your applications identity to the token issuing endpoint. You do this by means of a signed assertion. We require that this assertion is based on a private key, as service apps are quite powerful we believe this is the correct approach.

    8. There is currently no other way for an app to authorize / install into a tenant than doing #4.

    Hope this helps.

    Thank you,

    Matthias

    1. suresh says:

      Hi Matthias,

      You have mentioned the OneDrive does not support App Tokens yet on June 16, 2015 at 8:49 pm. Can you update me the current status of the same. I am looking to access all user’s file through admin user token, like accessing the mails and contacts through office365 API.

      Thanks,
      Suresh

  56. Mix Kira says:

    Hi Matthias, and thanks for the answer!

    1) Uh, Well… I think that is very useful to have in the future!

    3) If I call the token endpoint, I don't need that, but if I call the authorize endpoint, without it, I get an html with the form back, with it, I get the "HTTP/1.1 100 Continue"

    4) so, if it's a daemon, how can I check if it's authorized?

    5) If I, in some way, check that I'm not authorized, and I call the authorize point with the certificate and login_hint (and he answer back to me the 100 Continue"), it doesn't work authorize the application? (without the need of browse to an url)

    7) Ok, in fact I get an access token, the app-only access token, right? (that could not be used for onedrive/new api)

    Only one report: I've tried and using the certificate or the client_secret on the token endpoint, always return a token without, that seam ok (so, it seam that there you don't need the certificate to get that token)

    Now I will have to study the normal authentication flow, and hope that could work in some way (I need to do a big batch operation on all the onedrive of my user, that's about 2100)

    I need to understand if, getting the authorization code once, and refreshing the token, I could execute a script that could work for hours…

    An other little question, that I haven't found: whats the new api call limit? It's application based or ip based?

    A little thing: I'm working in php, creating a little api client package for the new graph, in object oriented style, that represent the object and call that I will use of onedrive (and maybe the azure users). I probably haven't the time to finish it, but I could share, so someone could finish and do a sort php api client.

    I would let you know. In the case, can I put it on a repo somewhere?

    Thanks

    Mix

  57. Dmytro Panfylov says:

    Hi Mix

    4) I guess you will not get access token from assertion, any way your daemon should be configured with tenant id, easyiest way to get tennat id is to pass user via authorization flow. So idialy it will go so:

     – user visits webpage with button "install app"

     – after he clicks on normal oauth2 flow goes

     – during this flow tennant id is obtained.

     – daemon provisioned with tennant id

     – now daemon can get app only access tokens

  58. DimDim4000 says:

    Hi Matthias.

    When I upload the application manifest with keyCredentials for my self-issued certificate to Azure AD it says "Successful". But when downloading it for checking I find the "keyCredentials": [ { … , "value":  null }]. Is this normal behavior?

  59. Pranjal says:

    Is this a Security Issue in "Client credential flow"?

    Hi Matthias,

    I am trying a scenario in which I fetch OAuth token using approach you have explained in above document, without doing the first step i.e, "Granting consent and app authentication strength", I did not do Admin consent and directly call EWS Java API passing this OAuth token. It gives me data of users, and everyhting works.

    My questions is: if everything works without step 1 of admin consent, why that step is needed?

  60. Rama says:

    Hi Matthias,

    Is the certificate mandatory for client credentials flow ?

    I have made a Rest API call to my application token endpoint URL with client id and client secret and resource as "https://outlook.office365.com&quot;, I have got the access token, but with this token from a standalone java application, when I pass this in Authorization header with Bearer and this token, it gives 401 Unauthorized and when Trace is enabled, I get the following

    x-ms-diagnostics : 2000010;reason="The access token is acquired using an authentication method that is too weak to allow access for this application. Presented auth strength was 1, required is 2.";error_category="insufficient_auth_strength"

    When I tried to google for this insufficient auth strength, it says that X.509 certificates are mandatory, is that the way client credentials flow works ?

    Please let me know.

    Thanks and Regards,

    Rama.

  61. Rama says:

    x-ms-diagnostics : 2000010;reason="The access token is acquired using an authentication method that is too weak to allow access for this application. Presented auth strength was 1, required is 2.";error_category="insufficient_auth_strength"..

    When does this error come up? Is it when access token is acquired just with client id and client secret without X.509 certificates?

  62. Yes, certificates are mandatory and you will get that error if you just use a secret.

  63. Marcel says:

    I am using the example project from github.com/…/o365api-as-apponly-webapp and followed the instructions in the blog. I did the sign in and allowed a number of permissions to the app.

    Then when I try any operation on the Mail, Calender or Contacts it returns me the following error:

    { "error": "Unauthorized", "x-ms-diagnostics": "2000001;reason='The token is missing the claim type 'roles'.';error_category='invalid_token'" }

    Could you please tell me how I can fix this?

    Thanks in advance.

    Marcel

  64. Prashanth says:

    Hi Matthias,

    I created a self signed certificate with openssl to create .pem file.

    I open the file with text editor which had the string between —–BEGIN CERTIFICATE—–

    and —–END CERTIFICATE—–  

    , is that equivalent to base64value.

    How do i use openssl to get the base64 string

    Can you please help in generating the

    $bin = $cer.GetRawCertData()

    $base64Value = [System.Convert]::ToBase64String($bin)

    $bin = $cer.GetCertHash()

    $base64Thumbprint = [System.Convert]::ToBase64String($bin)

    $keyid = [System.Guid]::NewGuid().ToString()

  65. Marcel says:

    Figure it out already, I was setting Delegated Permissions instead of Application permissions.

    So this causes the error:

    { "error": "Unauthorized", "x-ms-diagnostics": "2000001;reason='The token is missing the claim type 'roles'.';error_category='invalid_token'" }

    Marcel

  66. Mayank says:

    Hi Matthias

    Thanks for valuable article it helps me a lot. but now i have to create calendar by this flow. can you suggest me the way.

    mayank

  67. Ree Shawn says:

    Hello Matthias,

    I just asked a question on Stack Overflow, could you please suggest?

    stackoverflow.com/…/building-daemon-or-service-apps-with-office-365-mail-secret-upload-automation

  68. Shekhar Sharma says:

    Hi,

    I have used ADAL JS to create a calendar app (Read Write). I have registered app in manage.windowsazure.com and successfully able to add Oauth2 for login, reading calendar event. But I can't do a POST request for event. It throws 400 error.

    I have posted more details here.

    stackoverflow.com/…/cant-create-post-event-in-office365-api-through-angularjs-adal-js

  69. Gaurang Patel says:

    Hi,

    I try to follow the same step that you have mention and able to get access token successfully but when i try to access call graph.windows.net/…/users it return 403 forbidden error. When i try to access with same parameter throug Graph explorer sand box it working perfect/ So i don't know where i made mistake… Pls help me …

    Thanks

    Gaurang

  70. 403 usually means you are passed authentication (token validation was passed), and now the API does access check against the requested resources and permissions in the token. You can decode the access token at http://jwt.calebb.net. Does it have the right permissions for the graph in the "roles" claim-type?

  71. Thomas Ebert says:

    Hi Matthias,

    Thank you very much for this insightful post!

    (Though, you could remove the Word formatting making it very hard to read. ;-))

    I have one question regarding the app permissions: We want to build a web app that has access to certain userβ€˜s calendars of our tenant (read/write) using client credential flow. But I don't want the app to have the ability to access *all user's* calendars. Is it possible to specify a certain access range for the app or only assign certain users? Can you help me there?

    Thanks

    Thomas

  72. Jonathan says:

    Great post! But like others, I'm running into issues.  I can click the link that redirects to Office365.  I accept to connect the app.  When redirecting to my app, I get an error in the 'consent' view when trying to set the access_token.  I manually went through the steps in the 'get_access_token' function and tried to make the post request in Advanced Rest Client, and I get a 400 error:

    {"error":"unauthorized_client","error_description":"AADSTS70002: Error validating credentials. AADSTS50064: Credential validation failed.rnTrace ID: 63b501c5-296a-4235-a7af-4296441721f0rnCorrelation ID: 5513b3b3-6e2e-4b37-927d-0b6bad48a515rnTimestamp: 2015-10-27 19:54:35Z","error_codes":[70002,50064],"timestamp":"2015-10-27 19:54:35Z","trace_id":"63b501c5-296a-4235-a7af-4296441721f0","correlation_id":"5513b3b3-6e2e-4b37-927d-0b6bad48a515"}

    Any ideas?

  73. Nankai Pan says:

    any update on the SharePoint support?

  74. stu mark says:

    When adding the value to the key credentials, should the base64 of the certificate data have the rn in it or not? There's a comment from somebody who had a problem with it, but he didn't actually say which way was the correct one.

  75. Sarang Padhye says:

    Hi Matthias ,

    Thank you for the blog. I have completed all the steps correctly but when I try to get all the events with the access token I get the following error message in the x-ms-diagnostics : reason="The token contains no permissions, or permissions can not be understood.";error_category="invalid_grant".

    I am using the following curl command

    curl -v outlook.office.com/…/events -H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsI……."

    Could you please help me to resolve this. Thanks.

  76. James Ferretti says:

    HI Matthias,

    Thanks for this article, it was a great help once I eventually found it!

    I'm having some issues with permissions when performing moves/deletes, please could you take a look at my SO post?

    stackoverflow.com/…/deleting-an-email-using-the-office-365-mail-rest-service-from-a-background-daemo

    Thank you,

    James

  77. Tommy says:

    Hi Matthias,

    The process described in the article works well. However, we'd like to offer our customers a simple solution that does not require an admin consent.

    It should allow users to view/edit events in meeting room calendars according to their permissions as allowed within the Office365 UI. Which version of the API/APP can support that?

    Thanks in advance,

    Tommy

  78. Shweta says:

    Hey Matthias,

    Would this work on on-premise environment?

  79. @Tommy: This sounds like you want to build a app a user signs-on to work with their calendars and calendars they have permissions (are shared with them). We're currently working on making this available and will introduce a new permissions "Calendars.ReadWrite.All" that will allow you to build such an app. The OAuth flow to use would be a regular code flow where the user consents to the app. I cannot give you a firm ETA for this work when it will light up in production, but it's not too far out.

    @Shweta:  We're looking to enable on-premises OAuth2 support targeting end of Q1/Q2 in two variations, in a pure on-premises deployment using ADFS 2016 as authorization server, and in a hybrid deployment where AAD can be the authorization server for on-premises.

  80. @Sarang. Did you resolve your issue? From the error returned by our auth module (in x-ms-diagnostics) it seems the app token has no app permissions in it. Make sure you select "Application Permissions" in the app registration and configure appropriate permissions for your app there. Once you get the app token you can copy&paste it into jwt.calebb.net and check if it contains a "roles" claim that expresses the app permissions you selected. If it has no "roles" claim something is not right with the app permission configuration.

  81. pwnell says:

    Hi Matthias,

    I followed your example in a Windows .NET Service application.  I am fine up to getting my tenant ID.  When I next try to use your method GetAppOnlyAccessToken using ADAL, I get this error:

    System.AggregateException: One or more errors occurred. —> Microsoft.IdentityModel.Clients.ActiveDirectory.AdalServiceException: AADSTS70002: Error validating credentials. AADSTS50012: Client assertion contains an invalid signature.

    Trace ID: b9140407-9452-4dfb-9667-263a3cff9dff

    Correlation ID: 0050f77c-967a-4a68-aed9-155d629a0cdd

    My certificate is correct, it was uploaded via manifest and I can confirm via downloading it that Azure accepted it.  It is 2048 bits long, and I am providing the correct private key.  What else can I look at?

  82. vives009 says:

    Hi,

    I was able to get access token and when I used this access token to access the Outlook Mail API via request, I was getting “401 Unauthorized” error.

    ERROR: x-ms-diagnostics: 2000001;reason=”The access token is acquired using an authentication method that is too weak to allow access for this application. Presented auth strength was 1, required is 2.”;error_category=”invalid_token”

    Can you please suggest?

  83. Nitin says:

    Hi Matthias,
    Can a daemon using the client credentials flow subscribe to Notifications from a particular user’s mailbox using the Notifications Rest API? Is there any plans to support such a functionality?
    Stackoverflow link: http://stackoverflow.com/questions/37010223/office-365-mail-statistics

  84. Rohit Shrivastava says:

    In Client Credential Flow, while registering an application and grant delegation for just one user rather than all the users? I want to develop a deamon service which just polls one user office365 mailbox and I dont want to give access to this app to all the users.
    In the first paragraph of this article, “Essentially before the application can access data for a user, it has to get an access token/refresh token for each user, and to get those the user has to sign-on to the application at least once.” Once granted the access to email to application by a user, how long the refresh token would work, assuming user never changes his password, will it work forever?

    1. Paul says:

      Hi Matthias

      Like the previous comment, I want to develop a service type app using application permissions rather than asking the user to sign on. Effectively the app will have its own mailbox. It is for an institution and there is no way they will want to give Mail.Read to all mailboxes to a third party app. Is there any way of limiting access to a single mailbox and using this type of authentication?

      Thanks in advance for any ideas…

      Paul

  85. CC says:

    Hi — i have a test app working: i give consent to the app, an app-only token is granted via a client assertion, and i can read info from an arbitrary mailbox. Works great.

    But our app will be installed for various clients on their private machines — so it’s like a native app, but we need the global permissions that app-only tokens are required for (which is why we aren’t a native app).

    Since access tokens are granted only based on our app credentials, i think they won’t work for us: Customer A could get an access token for Customer B’s private data using just the app credentials and the tenant ID.

    Is there any way to restrict access tokens to only be granted for a particular tenant ID, based on some secret?

    Or is there a back-door way to get app-only style global access with a ‘native app’ architecture?

    Having each customer define an app of their own isn’t a realistic option, as it’s far too complicated for them, requires cert generation, editing the manifest, etc etc. (My understanding is that this is a “line of business / LOB” app and would require a setup similar to when i set up the test app. If there is a way to automate it, please clue me in.)

    If a cert could be restricted to a particular tenant ID, we could make a cert for each customer.

    Or if the app manifest has a “require client secret for app-only token generation and restrict calls to this tenant ID” option, i could make a key for each customer.

    Any such ideas are welcome! Thanks! I’m going to post this on stack overflow as well.

Skip to main content