Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to authenticate with Azure AD from iOS app using AppAuth?

I have this example working with Google as ID provider:

https://github.com/jchnxu/TestOIDAppAuth-iOS

The example is using the AppAuth library and Open Id Connect from iOS in Swift. I'm not using ADAL since it doesn't seem to support Swift 3.

My iOS app bundle is:

webinnovation.no.Test

I have configured the following constants in ViewController.swift:

let kIssuer = "https://accounts.google.com"
let kClientID = "<my id from Google>.apps.googleusercontent.com"
let kRedirectURI = "com.googleusercontent.apps. <my id from Google>:oauthredirect"

In plist.info: “com.googleusercontent.apps. <my id from Google>”

This works as expected with the Google Id provider. I get a login dialog and it is dismissed correctly after logging in and the application correctly gets a token.

But, how do I map this to Azure AD?

I tried with combinations like this:

let kIssuer = "https://login.microsoftonline.com/webinnovation.onmicrosoft.com"
let kClientID = "<my Application ID from Azure AD>"
let kRedirectURI = "no.webinnovation.Test://oauth/redirect"

In info.plist: "no.webinnovation.Test"

This kind of work. I get the Azure AD authentication dialog displayed on my iOS device, but after entering my credentials, the dialog does not get dismissed correctly and the application does not get any token back. The flow kind of stops. If I click on "Done" the Azure AD dialog disappears, but then the AppAuth call returns an error and the user is not authenticated.

I suspect there are some issues related to the Redirect URI, but I have not find a correct way to do it.

like image 381
OlavT Avatar asked May 11 '17 18:05

OlavT


People also ask

How do I authenticate an app using Azure AD?

Sign in to the Azure portal, search for and select App Services, and then select your app. Note your app's URL. You'll use it to configure your Azure Active Directory app registration. From the portal menu, select Azure Active Directory, then go to the App registrations tab and select New registration.

Which three items does a custom app need to authenticate with an Azure AD application?

Application authentication and authorization. User authentication and authorization. SSO using federation or password.

How do I enable Windows authentication in Azure App Service?

Go to your application in the Azure portal. Select Settings > Authentication / Authorization, and make sure that App Service Authentication is On. Under Authentication Providers, select Azure Active Directory.


2 Answers

Azure AD does actually support Swift 3 in our latest MSAL library and have code samples in Swift to help you out. However, App Auth is absolutely supported by Azure Active Directory. You just need to set up a redirect URI that has the ability to call back your application and use the correct Issuer for your tenant.

That is the problem you are running in to. Sign in is successful, but Azure can't find it's way back to your app!

First, some groundwork.

System Webviews

Most modern OAuth2 libraries now use the System Webview for signing a user in. A System Webview is a browser component that an application can launch that appears to be part of the application but is actually an isolated process which runs the operating system's web browser. For iOS this is the SFSafariViewController and on Android it is Chrome Custom Tabs.

The benefit of the System Webview for singing a user in are numerous, including:

  • Better security. An application can not access the credentials typed in to a System Webview as it's an isolated browser process.

    Today many applications use a username and password form or an embedded webview to get credentials. This allows an application to listen in and grab these credentials. Many companies have begun disallowing applications that have this kind of sign in. System Webviews ensures your app doesn't have this problem.

  • Single Sign-On. Once a user has signed in with the System Webview, a cookie is placed in the browser and that account is available to any application, preventing the need for a user to sign in to every app separately.

    As more consumers and businesses leverage phone SMS and other factors as additional steps, having to redo this step as well as use your password is getting very annoying for customers. System Webviews remove this problem.

  • Better control. A user can choose which account to provide the application, or add a brand new account in the System Webview if supported.

You've seen Google and Microsoft make the transition to this System Webview with our latest SDKs as well as update our identity services, and it's to give the customer these protections and features. App Auth from the OpenID project, which has code contributed by both Google and Microsoft engineers among others, also provides this support.

System Webview Needs To Return Back To Your App

One of the things that might have occurred to you reading the above is this:

If an application now calls a System Webview for sign-in, and has no control over it, how do I get the tokens I need back from the System Webview?

The answer is that you must leverage the mechanisms each operating system has to call back the application, and then use the redirectURI from the OAuth2 protocol to return the response back to that application using that mechanism. It's almost exactly like how this works in a web browser. You get redirected away from the website to an identity provider for sign in, and then the identity provider uses the redirectURI to return the user back to the website with tokens in the response somewhere.

For iOS this done through Custom URL Schemes. A URL scheme is in the format of CFBundleURLScheme:\\CFBundleURLSchemes and is defined as:

  • CFBundleURLName A string containing the abstract name of the URL scheme. To ensure uniqueness, it is recommended that you specify a reverse-DNS style of identifier, for example, com.acme.myscheme. The string you specify is also used as a key in your app’s InfoPlist.strings file. The value of the key is the human-readable scheme name.
  • CFBundleURLSchemes An array of strings containing the URL scheme names—for example, http, mailto, tel, and sms.

To register a URL type for your app, include the CFBundleURLTypes key in your app’s Info.plist file. The CFBundleURLTypes key contains an array of dictionaries, each of which defines a URL scheme the app supports.

How To Get A System Webview To Return To Your App

So, combining these two things, it's fairly simple what you need to do:

  1. Figure out what your URL scheme will be for your app (e.g. appauth://abc123.
  2. Tell Azure AD what your new URL scheme is, adding it as another redirectURI for your application.
  3. Configure your application to listen for this URL scheme and launch the app
  4. Configure the application itself to grab the token once this URL scheme launches your app (App Auth, as well our own MSAL libraries, do this for you!)

1. Figure out what your URL scheme will be for your app

You can read up on how to make URL schemes from Apple's Inter-App Communication documentation, but we recommend you use the scheme of appauth://<client id> (e.g. appauth://ab032846-efee-481f-b6bc-493aae92c432)

2. Tell Azure AD what your new URL scheme is

You need to add this URL scheme as a RedirectURI to your app. This is easy to do. Just visit https://apps.dev.microsoft.com/ and select your application. Scroll down to Custom App URIs under Native Applications and add your new redirectURI!

A snapshot of the place in the developer portal where you need to enter in this information

3. Configure your application to listen for this URL scheme

Add the following to your info.plist file as per Apple's instructions in Inter-App Communication. It should look something like this, although different apps will have different and additional URL schemes registered:

  <key>CFBundleURLTypes</key>
    <array>
        <dict>
            <key>CFBundleTypeRole</key>
            <string>Editor</string>
            <key>CFBundleURLName</key>
            <string>ab032846-efee-481f-b6bc-493aae92c432</string>
            <key>CFBundleURLSchemes</key>
            <array>
                <string>app-auth</string>
            </array>
        </dict>
    </array>

4. Configure the application itself to grab the token

Although listening for a response back from a web browser to an application is a well known pattern for all iOS apps, the actual implementation varies by the identity SDK you use, so you should check with the documentation. It's important you do this right. For App Auth they tell you to put the following code in your AppDelegate.m file:

/*! @brief Handles inbound URLs. Checks if the URL matches the redirect URI for a pending
        AppAuth authorization request.
 */
- (BOOL)application:(UIApplication *)app
            openURL:(NSURL *)url
            options:(NSDictionary<NSString *, id> *)options {
  // Sends the URL to the current authorization flow (if any) which will process it if it relates to
  // an authorization response.
  if ([_currentAuthorizationFlow resumeAuthorizationFlowWithURL:url]) {
    _currentAuthorizationFlow = nil;
    return YES;
  }

  // Your additional URL handling (if any) goes here.

  return NO;
}

The code is rather easy to understand once you know the background above :this is all about receiving a response from the identity service by grabbing the URL that is returned and then giving everything in that URL back to the app so it can grab the tokens it needs to continue it's work.

That's it!

Your app should now work with Azure Active Directory. This pattern of the System Webview is common both across many Identity Providers (Microsoft, Google, Facebook) and mobile platforms.

Bonus Content

As I said above, Microsoft is an OpenID working group contributor and supports App Auth development. As such, here is a pull request and should help you through any issues here: https://github.com/brandwe/AppAuth-iOS/tree/dev/Examples

It currently has an issue using the /common endpoint, but otherwise all the solution I mentioned above is represented in code there!

like image 104
Brandon Avatar answered Nov 10 '22 00:11

Brandon


So even though this question was asked quite a while ago, I just ran into this exact same problem and managed to fix it, so I want to document how.

The problem is caused by the fact that Azure AD appends a / at the end of the redirect URI if it does not already end with a /. So in this case, the redirect URI is no.webinnovation.Test://oauth/redirect and Azure AD will answer with something like no.webinnovation.Test://oauth/redirect/?code=....

AppAuth validates the redirect URI and determines that it is not the same, because of the additional / at the end. And in that case, it simply aborts the login flow and does not call the completion block with an error, which I would have expected.

So the solution is to simply add the / yourself, i.e. in this example use no.webinnovation.Test://oauth/redirect/ as the redirect URI.

like image 21
Holger Avatar answered Nov 10 '22 00:11

Holger