Search code examples
c#office365outlook-addinoffice365-appsoffice365api

Implement outlook calendar api in outlook add-in


I'm trying to implement the Office365 Outlook Calendar API inside the Outlook 365 Add-in. The Outlook Calendar API is fully implemented in the web application. Everything works fine with OAuth2 and the returned auth_token in the web application.

I'm having issues to sign in with OAuth2 inside the add-in. If you open the OAuth2-Login by Microsoft inside the add-in, it opens a Internet Explorer instance once you entered your appdev****@outlook[dot]com-account. This does not work with the auth_token saved in the session.

I tried to save the auth_token in a database (see //Test part) and request it for the user inside the add-in. This errors with a DataServiceClientException: Unauthorized Unknown location.

    [Route("SignIn")]
    public async Task<ActionResult> SignIn()
    {
        string authority = "https://login.microsoftonline.com/common";

        string clientId = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
        AuthenticationContext authContext = new AuthenticationContext(authority);

        Uri redirectUri = new Uri(Url.Action("Authorize", "outlook", null, HttpContext.Request.Scheme));

        Uri authUri = await authContext.GetAuthorizationRequestUrlAsync(scopes, null, clientId,
            redirectUri, UserIdentifier.AnyUser, null);

        return Redirect(authUri.ToString());
    }

    [Route("Authorize")]
    public async Task<ActionResult> Authorize()
    {
        string authCode = Request.Query["code"];

        string authority = "https://login.microsoftonline.com/common";

        string clientId = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
        string clientSecret = "xxxxxxxxxxxx";
        AuthenticationContext authContext = new AuthenticationContext(authority);

        Uri redirectUri = new Uri(Url.Action("Authorize", "outlook", null, HttpContext.Request.Scheme));

        ClientCredential credential = new ClientCredential(clientId, clientSecret);

        try
        {
            var authResult = await authContext.AcquireTokenByAuthorizationCodeAsync(
                authCode, redirectUri, credential, scopes);

            HttpContext.Session.SetString("access_token", authResult.Token);
            HttpContext.Session.SetString("user_email", GetUserEmail(authContext, clientId));

            //*** TEST ***
            _dbContext.ApplicationUsers.FirstOrDefault(e => e.Email == "appdev****@outlook.com").AccessToken = authResult.Token;
            _dbContext.ApplicationUsers.FirstOrDefault(e => e.Email == "appdev****@outlook.com").Email = GetUserEmail(authContext, clientId);

            return Content("Access Token: " + authResult.Token + " Email: " + GetUserEmail(authContext, clientId));
        }
        catch (AdalException ex)
        {
            return Content(string.Format("ERROR retrieving token: {0}", ex.Message));
        }
    }

Solution

  • New answer This is a common problem with Office add-in new generation (formerly App for Office) and OAUTH authentication. The fact that the add-in runs in a sandboxed iFrame force the authentication to be made in a popup window. There are also some problems to retrieve the auth token in the parent (sandboxed iFrame) window because frame communications are forbidden in this context. I proposed a solution here but the best solution comes from Richard DiZerega and is proposed here. From what I have understood, you try to save the auth_token in a database so it will be requested by the iFrame add-in later on. It is closed to what Richard DiZerega proposes.

    Old mistaken answer You are facing this issue because you probably registered you Azure AD app as a web application. Now you are requesting it with a native client without any 'url location' that is why this is failing.

    There is a different authentication scenario for native client.

    I think this is no big deal just register another app in your Azure AD for native client (this is the first question asked when you create an app).