App to app sign in for Office for iOS and Office for Android¶
The normal flow to sign in to your service from Office for iOS or Office for Android uses the OS WebView where your web sign in experience is rendered inside the Office for iOS or Office for Android app. Optionally, an additional optimization can be done where the user can sign in using your app.
The app to app flow involves Office for iOS or Office for Android invoking your app through your app’s URL scheme to sign in to your service, and your app invoking Office for iOS or Office for Android when sign in is complete.
Sign in using your app¶
When signing in to your service is required (i.e. the first time a file is opened from your app into Office, or when the user explicitly adds your service as a place in Office for iOS or Office for Android), Office for iOS or Office for Android calls your bootstrapper to obtain the
authorization_uri
, which it displays in a UIWebView. In addition to theauthorization_uri
, you should return a set of UrlSchemes that can be used to invoke your app.Office for iOS or Office for Android will first attempt to use the UrlSchemes to invoke your app. If none are returned, or if none of them are registered (i.e. your app is not installed), Office for iOS or Office for Android will fall back to the UIWebView.
If the user does have your app installed, your app will be invoked via the UrlSchemes, and the user will be sent to your app to complete authentication. If the user declines to open your app, Office for iOS or Office for Android will fall back to the UIWebView.
Once inside your app, you should do whatever is needed to obtain the user’s auth code (for example, display “Grant permission to Office” dialog or ask for additional sign ins).
Return the user to the Office for iOS or Office for Android app with the auth code via the Office URL scheme (see below).
Office for iOS Specific changes¶
URL scheme design¶
The data passed via the URL scheme is essentially the same as would be passed via authorization_uri
.
Here is an example of a normal authorization_uri
with parameters added. The parameters are described in
RFC6749.
Invoking the sign in screen:
https://contoso.com/api/oauth2/authorize?client_id=abcdefg&redirect_uri=https%3A%2F%2Flocalhost&response_type=code&scope=&rs=en-US&Build=16.1.1234&Platform=iOS
Host’s redirect URL that ends the OAuth flow:
https://localhost?state=&code=abcdefg&tk=https%3A%2F%2Fcontoso.com%2Fapi%2Ftoken%2F%3Fextra%3Dstuff
The same parameters are passed via the URL Schemes, with the addition of “action”.
Office for iOS invoking your app (“To” URL):
Contoso:client_id=abcdefg&response_type=code&scope=wopi&rs=enUS&build=16.1.1234&platform=iOS&app=word&action=76d173ad-a43f-4e3c-a5e7-0e7276b4c624
Your app invoking Office for iOS (“Back” URL):
ms-word-tp:code=abcdefg&tk=https%3A%2F%2Fcontoso.com%2Fapi%2Ftoken%2F%3Fextra%3Dstuff&sc=xyz&action=76d173ad-a43f-4e3c-a5e7-0e7276b4c624
The values of the parameters should be URL encoded.
If authentication fails, the error parameters per RFC6749 can also be passed back to Office for iOS via the URL schemes, just as they can be passed back to Office for iOS via the redirect URI in the UIWebView model.
New URL schemes registered by Office for iOS¶
ms-word-tp
ms-excel-tp
ms-powerpoint-tp
ms-officemobile-tp
These are for Word, Excel, and PowerPoint respectively. Use these to invoke Office for iOS when the user is done with authentication on your side.
Action parameter¶
Action is a string passed to your app that should be passed back to Office unchanged.
Office for Android Specific changes¶
Service-side Changes¶
Adding information to the WWW-Authenticate response header on unauthenticated bootstrap requests
Office for Android will use Intent to invoke your App. The information Office needs are your App’s Package name, Auth activity name and Version code. Office will consider provided Version code as the base version and will assume that your App with this Version and above will support App to App authentication.
The information Office needs is passed via the URLScheme parameter in the WWW-Authenticate response header to unauthenticated bootstrap request.
Parameter |
Value |
Required |
Example |
---|---|---|---|
|
n/a |
Yes |
Bearer |
|
The URL of the OAuth2 Authorization Endpoint to begin authentication against as described at: RFC 6749#section-3.1 |
Yes |
|
|
The URL of the OAuth2 Token Endpoint where authentication code can be redeemed for an access and (optional) refresh token. See Token EndPoint at: RFC 6749#section-3.2 |
Yes |
|
|
A well-known string (as registered with
with Microsoft Office) that uniquely
identifies the host.
Allowed characters: |
No |
TP_CONTOSO |
|
Information used to invoke your app (despite the name of the parameter, this may not always be URL schemes; e.g. on Android, intent is used). This is an ordered list by platform. Omit any platforms you do not support. Office will attempt to invoke these in order before falling back to the WebView auth. |
No |
{
"iOS": [
"contoso",
"contoso-EMM"
],
"Android": [
"Package1VersionCode",
"Package1Name",
"Package1AuthActivityName",
"Package2VersionCode",
"Package2Name",
"Package2AuthActivityName"
],
"UWP": [...]
}
|
Client-side Changes¶
Invoking your App on Android
Office will create an intent, which will take the package name and auth activity name of your App. We will set following two extras to intent:
AuthorizeUrlQueryParams
: It is exactly same as used in iOS without theaction
parameter. e.g.:client_id=abcdefg&response_type=code&scope=wopi&rs=enUS&build=16.1.1234&platform=android&app=word
UserId
: It will be an optional parameter and will be set whenever we will have it. Third party should use to verify that the sign in requested for the User signed in to their App.
1 2 3 4 5 6 7 8 | protected void LaunchIntent()
{
Intent authIntent = new Intent();
authIntent.setComponent(new ComponentName("com.android.thirdparty.packagename", " com.android.thirdparty.packagename.AuthActivityName"));
authIntent.putExtra(AuthorizeUrlQueryParams, client_id=abcdefg&response_type=code&scope=wopi&rs=enUS&build=16.1.1234&platform =android&app=word);
authIntent.putExtra(UserId, User123);
startActivityForResult(authIntent, uniqueRequestCode)
}
|
After this Office will wait for result and will expect following from third party App
ResponseUrlQueryParams
: Again this is exactly same as what we are getting in iOS minus theaction
parameter. The following are values of it in success and failure cases:code=abcdefg&tk=http://contoso.com&sc=xyz
[during RESULT_OK]error=invalid_request&error_description="optional human readable message"
[during RESULT_CANCELLED or anything else]
UserId
: Third party should send which user is authenticated by it. Office will use it to show error in caseUserId
in request and response mismatch.
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | protected void onActivityResult(int requestCode, int resultCode, Intent result)
{
// Check which request we're responding to
if (requestCode == uniqueRequestCode)
{
// Make sure the auth request was successful
if (resultCode == RESULT_OK)
{
//successfully authed
// Here we will assume that result will contain ResonponseUrlQueryParams
// which will look like this code=abcdefg&tk=http://contoso.com&sc=xyz
}
else if (resultCode == RESULT_CANCELED)
{
//auth request cancel
// Here we will assume that result will contain ResonponseUrlQueryParams
// But this time we will not get tk and session context but may get error and error_description.
}
}
else
{
//failed
// Here we will assume that result will contain ResonponseUrlQueryParams
// But this time we will not get tk and session context but may get error and error_description.
}
}
|
This is the work which your App needs to do
Add an intent filter to AndroidManifest.xml
1 2 3 4 5 6 7 | <activity android:name="AuthActivityName">
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
</intent-filter>
</activity>
|
Handle the intent in AuthActivity
2 3 4 5 6 7 8 9 | protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
// Get the intent that started this activity
Intent intent = getIntent();
// Get the bundle of Extras, it will have data set by caller App
Bundle extras = intent.getExtras();
}
|
Returning result
11 12 13 14 15 16 17 18 | protected void returnResult()
{
// create intent to deliver result data
Intent result = new Intent();
resut.putExtra("ResonponseUrlQueryParams", "code=abcdefg&tk=http://contoso.com&sc=xyz");
setResult(Activity.RESULT_OK, result);
finish();
}
|
More details here https://developer.android.com/training/basics/intents/filters.html#ReturnResult