Get started with Microsoft Graph in an Android app

Building apps for enterprise customers? Your app may not work if your enterprise customer turns on enterprise mobility security features like conditional device access. In this case, you may not know and your customers may experience errors.

To support all enterprise customers across all enterprise scenarios, you must use the Azure AD endpoint and manage your apps using the Azure Management Portal. For more information, see Deciding between the Azure AD and Azure AD v2.0 endpoints.

This article describes the tasks required to get an access token from the Azure AD v2.0 endpoint and call Microsoft Graph. It walks you through building the Connect Sample for Android and explains the main concepts that you implement to use Microsoft Graph in your app for Android. The article also describes how to access Microsoft Graph by using either the Microsoft Graph SDK for Android or raw REST calls.

To use Microsoft Graph in your app for Android, you need to show the Microsoft sign in page to your users, as shown in the following screenshot.

Sign in page for Microsoft accounts on Android

Don't feel like building an app? Get up and running fast by downloading the Connect Sample for Android that this article is based on.

Prerequisites

To get started, you'll need:

Configure a new project

If you have downloaded the Connect Sample for Android, skip this step.

Start a new project in Android Studio. You can leave the default values for most of the wizard, just make sure to choose the following options:

  • Target Android Devices - Phone and Tablet
    • Minimum SDK - API 16: Android 4.1 (Jelly Bean)
  • Add an Activity to Mobile - Basic Activity

This provides you with an Android project with an activity and a button that you can use to authenticate the user.

Register the application

You need to register your app on the Microsoft App Registration Portal whether you've downloaded the connect sample or created a new project.

Register an app on the Microsoft App Registration Portal. This generates the app ID that you'll use to configure the app.

  1. Sign into the Microsoft App Registration Portal using either your personal or work or school account.

  2. Choose Add an app.

Tip: If you have downloaded the Connect Sample for Android and are just creating a registration for it, uncheck Guided Setup before chosing the Create button.

  1. Enter a name for the app, and choose Create.

    For the Guided Setup flow:

    a. Choose Mobile and Desktop App to define the kind of app you are creating.

    b. Choose Android to define the mobile technology you are using.

    c. Review the introductory topic and when finished, click the Setup button at the end of the page.

    d. Follow the instructions on the Setup step to add the MSAL library to your app build.gradle.

    e. Follow the directions on the Use step to add MSAL logic to your new project

    f. On the Configure page, the portal has created a unique application ID for you. Use it to configure your app.

    For the unguided flow:

    The registration page displays, listing the properties of your app.

    a. Copy the application ID. This is the unique identifier for your app.

    b. Choose Add Platform and Native Application.

    Note: The Application Registration Portal provides a Redirect URI with a value of msalYOUR NEW APP ID://auth. Do not use the built-in redirect URIs. The Connect Sample for Android implements the MSAL authentication library which requires this redirect URI. If using a supported third party library or the ADAL library then you must use the built-in redirect URIs.

    For Guided Setup flow and unguided flow

    a. Add delegated permissions. You'll need profile, Mail.ReadWrite, Mail.Send, Files.ReadWrite, and User.ReadBasic.All.

    b. Choose Save.

Authenticate the user and get an access token

Note: If you followed the instructions in the Guided Setup flow from the application registration portal to create a new application, you can skip these steps. Go to Call Microsoft Graph using the Microsoft Graph SDK to learn more about the Graph API.

Let's walk through the Connect Sample for Android to learn about the MSAL and Microsoft Graph code we've added.

Add the dependency to app/build.gradle

Open the build.gradle file in the app module and find the following dependency:

    compile ('com.microsoft.identity.client:msal:0.1.+') {
        exclude group: 'com.android.support', module: 'appcompat-v7'
    }
    compile 'com.android.volley:volley:1.0.0'

Start the authentication flow

  1. Open the AuthenticationManager file and find the PublicClientApplication object declaration and then the instation in the getInstance method.
    private static PublicClientApplication mPublicClientApplication;
    ....

    public static synchronized AuthenticationManager getInstance() {
        if (INSTANCE == null) {
            INSTANCE = new AuthenticationManager();
            if (mPublicClientApplication == null) {
                mPublicClientApplication = new PublicClientApplication(Connect.getInstance());
            }
        }
        return INSTANCE;
    }

  1. In the ConnectActivity class, locate the event handler for the click event of the mConnectButton. Find the onClick method and review relevant code.

    The connect method enables personally identifyable information (PII) logging, gets an instance of the sample helper class AuthenticationManager, and gets the MSAL platform object users collection. If there are no users, the new user is taken to the Azure AD authentication and authorization flow. Otherwise, an authentication token is obtained silently.

    @Override
    public void onClick(View view) {
        ....
        connect();
    }

        private void connect() {

        if (mEnablePiiLogging) {
            Logger.getInstance().setEnablePII(true);
        } else {
            Logger.getInstance().setEnablePII(false);
        }

        AuthenticationManager mgr = AuthenticationManager.getInstance();

        List<User> users = null;

        try {
            users = mgr.getPublicClient().getUsers();

            if (users != null && users.size() == 1) {
                mUser = users.get(0);
                mgr.callAcquireTokenSilent(mUser, true, this);
            } else {
                mgr.callAcquireToken(
                        this,
                        this);
            }
        } catch (MsalClientException e) {
            Log.d(TAG, "MSAL Exception Generated while getting users: " + e.toString());

        } catch (IndexOutOfBoundsException e) {
            Log.d(TAG, "User at this position does not exist: " + e.toString());
        }
    }

  1. Find the event handler that processes the Azure AD redirect response generated by Azure AD when the user closes the authintication dialog. This handler is in the ConnectActivity class.
       /**
     * Handles redirect response from https://login.microsoftonline.com/common and
     * notifies the MSAL library that the user has completed the authentication
     * dialog
     * @param requestCode
     * @param resultCode
     * @param data
     */
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (AuthenticationManager
                .getInstance()
                .getPublicClient() != null) {
            AuthenticationManager
                    .getInstance()
                    .getPublicClient()
                    .handleInteractiveRequestRedirect(requestCode, resultCode, data);
        }
    }

  1. Find the authentication callback method that caches the authentication token that is used in Graph API calls.
    /* Callback used for interactive request.  If succeeds we use the access
         * token to call the Microsoft Graph. Does not check cache
         */
    private AuthenticationCallback getAuthInteractiveCallback() {
        return new AuthenticationCallback() {
            @Override
            public void onSuccess(AuthenticationResult authenticationResult) {
            /* Successfully got a token, call graph now */
                Log.d(TAG, "Successfully authenticated");
                Log.d(TAG, "ID Token: " + authenticationResult.getIdToken());

            /* Store the auth result */
                mAuthResult = authenticationResult;
                if (mActivityCallback != null)
                    mActivityCallback.onSuccess(mAuthResult);
            }

            @Override
            public void onError(MsalException exception) {
            /* Failed to acquireToken */
                Log.d(TAG, "Authentication failed: " + exception.toString());
                if (mActivityCallback != null)
                    mActivityCallback.onError(exception);
            }

            @Override
            public void onCancel() {
            /* User canceled the authentication */
                Log.d(TAG, "User cancelled login.");
            }
        };
    }

The connect sample app has a Connect button on the main activity. If you press the button, on first use, the app presents an authentication page using the device's browser. The next step is to handle the code that the authorization server sends to the redirect URI and exchange it for an access token.

Exchange the authorization code for an access token

You need to make your app ready to handle the authorization server response, which contains a code that you can exchange for an access token.

  1. We need to tell the Android system that Connect app can handle requests to the redirect URL configured in the application registration. To do this open the AndroidManifest file and add the following children to the projects <application/> element.
        <uses-sdk tools:overrideLibrary="com.microsoft.identity.msal" />
        <application ...>
            ...
            <activity
                android:name="com.microsoft.identity.client.BrowserTabActivity">
                <intent-filter>
                    <action android:name="android.intent.action.VIEW" />
                    <category android:name="android.intent.category.DEFAULT" />
                    <category android:name="android.intent.category.BROWSABLE" />
                    <data android:scheme="msalENTER_YOUR_CLIENT_ID"
                        android:host="auth" />
                </intent-filter>
            </activity>
            <meta-data
                android:name="https://login.microsoftonline.com/common"
                android:value="authority string"/>
            <meta-data
                android:name="com.microsoft.identity.client.ClientId"
                android:value="ENTER_YOUR_CLIENT_ID"/>
        </application>
  1. The MSAL library needs access to the application Id assigned by the registration portal. The MSAL library refers to the application Id as the "Client Id". It gets the application Id (Client Id) from the application context that you pass in the library constructor.

Note: You can also provide the client Id at run-time by passing a string parameter to the constructor.

  1. The activity is invoked when the authorization server sends a response. Request an access token with the response from the authorization server. Go to your AuthenticationManager and find the following code in the class.
    /**
     * Authenticates the user and lets the user authorize the app for the requested permissions.
     * An authentication token is returned via the getAuthInteractiveCalback method
     * @param activity
     * @param authenticationCallback
     */
    public void connect(Activity activity, final MSALAuthenticationCallback authenticationCallback){
        mActivityCallback = authenticationCallback;
        mPublicClientApplication.acquireToken(
                activity, Constants.SCOPES, getAuthInteractiveCallback());
    }


     /* Callback used for interactive request.  If succeeds we use the access
         * token to call the Microsoft Graph. Does not check cache
         */
    private AuthenticationCallback getAuthInteractiveCallback() {
        return new AuthenticationCallback() {
            @Override
            public void onSuccess(AuthenticationResult authenticationResult) {
            /* Successfully got a token, call graph now */
                Log.d(TAG, "Successfully authenticated");
                Log.d(TAG, "ID Token: " + authenticationResult.getIdToken());

            /* Store the auth result */
                mAuthResult = authenticationResult;
                if (mActivityCallback != null)
                    mActivityCallback.onSuccess(mAuthResult);
            }

            @Override
            public void onError(MsalException exception) {
            /* Failed to acquireToken */
                Log.d(TAG, "Authentication failed: " + exception.toString());
                if (mActivityCallback != null)
                    mActivityCallback.onError(exception);
            }

            @Override
            public void onCancel() {
            /* User canceled the authentication */
                Log.d(TAG, "User cancelled login.");
            }
        };
    }

     /**
     * Returns the access token obtained in authentication
     *
     * @return mAccessToken
     */
    public String getAccessToken() throws AuthenticatorException, IOException, OperationCanceledException {
        return  mAuthResult.getAccessToken();
    }

Call Microsoft Graph

You can use the Microsoft Graph SDK or the Microsoft Graph REST API to call Microsoft Graph.

Call Microsoft Graph using the Microsoft Graph SDK

The Microsoft Graph SDK for Android provides classes that build requests and process results from Microsoft Graph. Follow these steps to use the Microsoft Graph SDK.

  1. Add Internet permissions to your app. Open the AndroidManifest file and add the following child to the manifest element.
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

  1. Add dependencies to the Microsoft Graph SDK and GSON.
    compile 'com.microsoft.graph:msgraph-sdk-android:1.3.2'
    compile 'com.google.code.gson:gson:2.7'
  1. Add authentication token to new requests using the uthenticateRequest helper method. This method implements the same method from the Microsoft Graph Authentication IAuthenticationProvider interface
    /**
     * Appends an access token obtained from the {@link AuthenticationManager} class to the
     * Authorization header of the request.
     * @param request
     */
    @Override
    public void authenticateRequest(IHttpRequest request)  {
        try {
            request.addHeader("Authorization", "Bearer "
                    + AuthenticationManager.getInstance()
                    .getAccessToken());
            // This header has been added to identify this sample in the Microsoft Graph service.
            // If you're using this code for your project please remove the following line.
            request.addHeader("SampleID", "android-java-connect-sample");
        } catch (AuthenticatorException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }  catch (OperationCanceledException e) {
            e.printStackTrace();
        } catch (NullPointerException e) {
            e.printStackTrace();
        }
    }
  1. Create a draft email and send it using the following helper methods from the GraphServiceController helper class.
    /**
     * Creates a draft email message using the Microsoft Graph API on Office 365. The mail is sent
     * from the address of the signed in user.
     *
     * @param senderPreferredName The mail senders principal user name (email addr)
     * @param emailAddress        The recipient email address.
     * @param subject             The subject to use in the mail message.
     * @param body                The body of the message.
     * @param callback            The callback method to invoke on completion of the POST request
     */
    public void createDraftMail(
            final String senderPreferredName,
            final String emailAddress,
            final String subject,
            final String body,
            ICallback<Message> callback
    ) {
        try {
            // create the email message
            Message message = createMessage(subject, body, emailAddress);
            mGraphServiceClient
                    .getMe()
                    .getMessages()
                    .buildRequest()
                    .post(message, callback);

        } catch (Exception ex) {
            showException(ex, "exception on send mail","Send mail failed", "The send mail method failed");
        }
    }

        /**
     * Creates a new Message object 
     */
    Message createMessage(
            String subject,
            String body,
            String address) {

        if (address == null || address.isEmpty()) {
            throw new IllegalArgumentException("The address parameter can't be null or empty.");
        } else {
            // perform a simple validation of the email address
            String addressParts[] = address.split("@");
            if (addressParts.length != 2 || addressParts[0].length() == 0 || addressParts[1].indexOf('.') == -1) {
                throw new IllegalArgumentException(
                        String.format("The address parameter must be a valid email address {0}", address)
                );
            }
        }
        Message message = new Message();
        EmailAddress emailAddress = new EmailAddress();
        emailAddress.address = address;
        Recipient recipient = new Recipient();
        recipient.emailAddress = emailAddress;
        message.toRecipients = Collections.singletonList(recipient);
        ItemBody itemBody = new ItemBody();
        itemBody.content = body;
        itemBody.contentType = BodyType.html;
        message.body = itemBody;
        message.subject = subject;
        return message;
    }
    /**
     * Sends a draft message to the specified recipients
     *
     * @param messageId String. The id of the message to send
     * @param callback
     */
    public void sendDraftMessage(String messageId,
                                 ICallback<Void> callback) {
        try {

            mGraphServiceClient
                    .getMe()
                    .getMessages(messageId)
                    .getSend()
                    .buildRequest()
                    .post(callback);

        } catch (Exception ex) {
            showException(ex, "exception on send draft message ","Send draft mail failed", "The send draft mail method failed");
        }
    }

Call Microsoft Graph using the Microsoft Graph REST API

The Microsoft Graph REST API exposes multiple APIs from Microsoft cloud services through a single REST API endpoint. Follow these steps to use the REST API.

  1. Add Internet permissions to your app. Open the AndroidManifest file and add the following child to the manifest element.
    <uses-permission android:name="android.permission.INTERNET" />
  1. Add a dependency to the Volley HTTP library.
    compile 'com.android.volley:volley:1.0.0'
  1. Replace the line String accessToken = tokenResponse.accessToken; with the following code. Insert your email address in the placeholder marked with <YOUR_EMAIL_ADDRESS>.
    final String accessToken = tokenResponse.accessToken;

    final RequestQueue queue = Volley.newRequestQueue(getApplicationContext());
    String url ="https://graph.microsoft.com/v1.0/me/sendMail";
    final String body = "{" +
        "  Message: {" +
        "    subject: 'Sent using the Microsoft Graph REST API'," +
        "    body: {" +
        "      contentType: 'text'," +
        "      content: 'This is the email body'" +
        "    }," +
        "    toRecipients: [" +
        "      {" +
        "        emailAddress: {" +
        "          address: '<YOUR_EMAIL_ADDRESS>'" +
        "        }" +
        "      }" +
        "    ]}" +
        "}";

    final StringRequest stringRequest = new StringRequest(Request.Method.POST, url,
        new Response.Listener<String>() {
            @Override
            public void onResponse(String response) {
                Log.d("Response", response);
            }
        },
        new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                Log.d("ERROR","error => " + error.getMessage());
            }
        }
    ) {
        @Override
        public Map<String, String> getHeaders() throws AuthFailureError {
            Map<String,String> params = new HashMap<>();
            params.put("Authorization", "Bearer " + accessToken);
            params.put("Content-Length", String.valueOf(body.getBytes().length));
            return params;
        }
        @Override
        public String getBodyContentType() {
            return "application/json";
        }
        @Override
        public byte[] getBody() throws AuthFailureError {
            return body.getBytes();
        }
    };

    AsyncTask.execute(new Runnable() {
        @Override
        public void run() {
            queue.add(stringRequest);
        }
    });

Run the app

You're ready to try your Android app.

  1. Start your Android emulator or connect your physical device to your computer.
  2. In Android Studio, press Shift + F10 to run your app.
  3. Choose your Android emulator or device from the deployment dialog box.
  4. Tap the Floating Action Button on the main activity.
  5. Sign in with your personal or work or school account and grant the requested permissions.
  6. In the app selection dialog, tap your app to continue.

Check the inbox of the email address that you configured in Call Microsoft Graph. You should have an email from the account that you used to sign in to the app.

Next steps

See also