Office365 API - Admin accessing another users/room's calendar events

By hitting this request: https://outlook.office365.com/api/v1.0/users/[email protected]/events in a browser I can enter my admin username and password and get Calendar Events for that specific room. However when I try making this call from a native app with the admin authenticated I get this response: reason="The call should access the mailbox specified in the oauth token.";error_category="invalid_grant" How can I get calendar events for a specific room authenticated as the admin?


Solution 1:

At present we only allow access to mail, calendar and contacts belonging to the authenticated user. So, your scenario of an admin accessing the conf. room calendar is not supported at this time. Access to resources belonging to other users e.g. conf. room calendar is on our roadmap to support but we don't yet have a timeframe to share with you.

In the meantime, you have two options.

Option #1: If you are able to run the app on a server, you can build a service app that requires admin consent, but is authorized to access any mailbox in the Office 365 tenant. You will need to make your native app talk to the app running on the server. See this blog for more details.

Option #2: You can use our Exchange Web Services SOAP API to implement your scenario. See Office 365 shared calendars for more details on this option and relevant links.

Solution 2:

This small PLUG-N-COMPILE-RUN (woo-hoo!) Java Class should demo getting to a room resource user calendar of events. The Azure V2.0 REST API is not currently allowing one to do so. Make sure that the auth-user that authenticates to the Exchange service is a "delegate" to (or of) the room resource user calendar whose events you want to retrieve. Your Exchange/Office365 admin might need to set that up for you. I grabbed the Java EWS API here: Index of /maven2/com/microsoft/ews-java-api/ews-java-api/2.0/ ews-java-api-2.0.jar and the javadoc.jar which was a great reference. You can also use Maven, Gradle or other methods to integrate the API into your code if you go to the Github repo: https://github.com/OfficeDev/ews-java-api. The Getting Started Guide is...well...words escape me (for good reason). Put it this way, you'd better use your search engine a bit in order to figure out how to do other stuff! And looking through the classes in the Javadoc helped me a good deal. Enough blah-blah-blah... On to the code: (oh, I included all of the imports! I always hate it when I get a sample snippet of code and I have to go hunting and pecking for the imports. I still leave it to you to get hooked up the the actual libraries, though! You're not in code-diapers anymore, if you can get this far! ;-)

package com.on.and.play

import java.net.URI;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.text.DateFormat;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.text.SimpleDateFormat

import microsoft.exchange.webservices.data.core.service.item.Appointment;
import microsoft.exchange.webservices.data.core.service.schema.AppointmentSchema;
import microsoft.exchange.webservices.data.core.service.folder.CalendarFolder;
import microsoft.exchange.webservices.data.search.CalendarView;
import microsoft.exchange.webservices.data.credential.ExchangeCredentials;
import microsoft.exchange.webservices.data.core.ExchangeService;
import microsoft.exchange.webservices.data.core.enumeration.misc.ExchangeVersion;
import microsoft.exchange.webservices.data.search.FindItemsResults;
import microsoft.exchange.webservices.data.property.complex.FolderId;
import microsoft.exchange.webservices.data.search.FolderView
import microsoft.exchange.webservices.data.core.service.schema.FolderSchema
import microsoft.exchange.webservices.data.search.FindFoldersResults
import microsoft.exchange.webservices.data.search.filter.SearchFilter
import microsoft.exchange.webservices.data.core.enumeration.search.FolderTraversal
import microsoft.exchange.webservices.data.core.service.item.Item;
import microsoft.exchange.webservices.data.core.service.schema.ItemSchema;
import microsoft.exchange.webservices.data.property.complex.Mailbox
import microsoft.exchange.webservices.data.search.ItemView;
import microsoft.exchange.webservices.data.core.PropertySet;
import microsoft.exchange.webservices.data.property.definition.PropertyDefinition
import microsoft.exchange.webservices.data.credential.WebCredentials;
import microsoft.exchange.webservices.data.core.enumeration.property.WellKnownFolderName;
import microsoft.exchange.webservices.data.core.enumeration.property.BasePropertySet;
import microsoft.exchange.webservices.data.core.exception.service.local.ServiceLocalException
import java.net.URI;

class MyTestService {
  public List getRoomCalendar() {       
    ExchangeService service = new ExchangeService(ExchangeVersion.Exchange2010_SP2);
    // replace [email protected] with a real email address that is
    // a delegate of [email protected]. Your exchange admin may  
    // need to set that up for you. 
    ExchangeCredentials credentials 
        = new WebCredentials("[email protected]",
                             "their_plain_text_password_God_bless_Microsoft");
    service.setCredentials(credentials);
    service.setUrl(new URI("https://outlook.office365.com/EWS/Exchange.asmx"));
    // service.autodiscoverUrl("[email protected]", );
    FolderView fv = new FolderView(100);
    fv.setTraversal(FolderTraversal.Deep);
    // replace [email protected] with your resource's email address 
    FolderId confRoomFolderId = new FolderId(WellKnownFolderName.Calendar, 
                                             new Mailbox("[email protected]"));
    List apntmtDataList = new ArrayList();          
    Calendar now = Calendar.getInstance();
    Date startDate = Calendar.getInstance().getTime();
    now.add(Calendar.DATE, 30);
    Date endDate = now.getTime();
    try {
      CalendarFolder calendarFolder = CalendarFolder.bind(service, confRoomFolderId);
      CalendarView cView = new CalendarView(startDate, endDate, 5);
      cView.setPropertySet(new PropertySet(AppointmentSchema.Subject, 
                                           AppointmentSchema.Start,
                                           AppointmentSchema.End));
      // we can set other properties as well depending upon our need.
      FindItemsResults appointments = calendarFolder.findAppointments(cView);
      List<Appointment> appList = appointments.getItems();
      for (Appointment appointment : appList) {
        Map appointmentData = new HashMap();
        appointmentData = readAppointment(appointment);
        apntmtDataList.add(appointmentData);
      }
    } catch (Exception e) {
      e.printStackTrace();
    }
    return apntmtDataList;
  } 

  public Map readAppointment(Appointment appointment) {
    Map appointmentData = new HashMap();
    try {
      DateFormat df = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss");
      appointmentData.put("appointmentItemId", appointment.getId().toString());
      appointmentData.put("appointmentSubject", appointment.getSubject());
      appointmentData.put("appointmentStartTime", df.format(appointment.getStart()));
      appointmentData.put("appointmentEndTime", df.format(appointment.getEnd()));
    } catch (ServiceLocalException e) {
      e.printStackTrace();
    }       
    return appointmentData;
  }
}