Use the Authentication Manager

Your app may need to access services that are restricted to authorized users. For example, your organization may host private data layers or feature services that are only accessible by verified users. You may also need to take advantage of premium ArcGIS Online services, such as routing, that require secured user access. The ArcGIS platform provides many ways to secure access to your organization's content and services. The Runtime SDK provides full support for access to secured ArcGIS Server, ArcGIS Online, or ArcGIS for Portal resources using the following authorization methods:

  • ArcGIS Tokens: proprietary token-based authentication mechanism
  • OAuth 2.0: secure delegated access to server resources
  • Network credential: HTTP secured service / Integrated Windows Authentication (IWA)
  • Certificate: Public Key Infrastructure (PKI)

Implementing these security methods in your app (potentially for a variety of platforms) can be a lot of work. Fortunately, ArcGIS Runtime SDK provides a component that abstracts much of the authentication logic for you, called AuthenticationManager. This class can be configured to react to security issues encountered in your app (such as requests for secured resources) by using a pre-defined credential, prompting the user for the correct type of credential required by the server, or other custom logic you define.

Authentication manager overview

To abstract some of the low-level details for working with secure resources, authentication manager handles some of the details when accessing secured resources in your app, such as challenging the user for credentials when a secured resource is accessed and storing credentials when the user successfully authorizes. It also manages a collection of server information and available user credentials if they have been provided. When a request for a secured resource is made to one of the registered servers, the authentication manager automatically includes the stored credentials in the request or handles getting a credential if one does not exist.

AuthenticationManager is a singleton class, which means there is always exactly one instance. You cannot instantiate an object of this type in your code, instead you must reference it using the Current static property.

Depending on the authorization method and platform for your app, the authentication manager may require a minimum amount of configuration to handle authenticating a user, including showing its own UI for gathering login information. In some situations, you may need more control over the authentication process by customizing the default handler.

Register servers with the authentication manager

Within your app, authentication manager maintains a collection of information about servers that require authentication to access secured services. You can register a server with the authentication manager by providing its URL and the type of authorization required. Registering a server is not always necessary, as authentication manager can usually determine the URI of a secured server as well as the token endpoint (for ArcGIS Token secured resources, for example) when a secured resource is encountered. For some types of authorization, you must register the server to provide additional information to properly describe authorization parameters for the server. OAuth authentication, for example, requires a unique ID for the client app and a URL to handle the response (and may require a client secret as well). In general, you register these servers when your app initializes to ensure that the authentication manager knows how to handle requests for their services.

The following example registers a server with the authentication manager with an OAuth (implicit) authentication type and defines some required information about the client app.

// Register a portal that uses OAuth authentication with the AuthenticationManager 
Esri.ArcGISRuntime.Security.ServerInfo serverInfo = new ServerInfo
{
    ServerUri = new Uri("https://www.arcgis.com/sharing/rest"),
    TokenAuthenticationType = TokenAuthenticationType.OAuthImplicit,
    OAuthClientInfo = new OAuthClientInfo { ClientId = "2HEtx9ujil5rac8K", RedirectUri = new Uri("https://developers.arcgis.com") }
};

AuthenticationManager.Current.RegisterServer(serverInfo);
Caution:

If using the Xamarin.Auth component in an Android or iOS app, the redirect URL for OAuth authorization must represent a valid endpoint. Arbitrary URLs, such as http://my.app.redirect or urn:ietf:wg:oauth:2.0:oob, for example, will return a 400 - Bad Request error. For iOS apps, all OAuth related URLs should be https.

If a request for a secured resource is made by your app, authentication manager includes a credential (if available) or makes the appropriate challenge for one.

Challenge the user for credentials

A challenge by the authentication manager occurs when a request is made to access a secured resource for which the authentication manager has no credential. A challenge can be resolved (handled, in other words) by providing the appropriate credential either programmatically or by prompting the user. A challenge handler associated with the authentication manager contains the logic to determine how to resolve challenges for secured resources.

Authentication manager stores server information and credentials

When a request is made for a secured resource, the authentication manager determines whether the request is to one of its registered servers. If a credential is already available for the server, the authentication manager automatically includes it with the request. Otherwise, the challenge handler logic determines how to resolve the challenge, perhaps by automatically generating a credential for the service or (more commonly) by prompting the user for login information according to the authorization method that's been defined for the registered server. This type of challenge is referred to as an on-demand challenge, because it only occurs when a request to a secured resource is made.

The following code will cause a challenge if the server is secured and does not allow anonymous (public) access.

// this code may cause an on-demand challenge or result in anonymous access
ArcGISPortal portal = await ArcGISPortal.CreateAsync(new Uri(SERVER_URI));

A server, however, often contains both secured and public (unsecured) resources. If the server in the preceding example allows public access for some of its resources, an on-demand challenge is not raised by the authentication manager. Instead, the user would simply be granted anonymous access. To explicitly challenge the user for a specified server, you need to issue a proactive challenge.

The following example creates a CredentialRequestInfo that defines the server to authenticate with. A proactive challenge is then issued by calling AuthenticationManager.GetCredentialAsync().

// define the credential request
CredentialRequestInfo cri = new CredentialRequestInfo
{
    // token authentication
    AuthenticationType = AuthenticationType.Token,
    // define the service URI
    ServiceUri = new Uri(ServerUrl),
    // OAuth (implicit flow) token type
    GenerateTokenOptions = new GenerateTokenOptions
    {
        TokenAuthenticationType = TokenAuthenticationType.OAuthImplicit
    }
};

// issue a proactive challenge by explicitly getting a credential
Credential cred = await AuthenticationManager.Current.GetCredentialAsync(cri, false);

The details of how a challenge for a credential is handled (user name and password, client certificate, hard-coded, entered by the user, and so on) are handled by the following components associated with the authentication manager.

  • Challenge handler - a component that implements the IChallengeHandler interface and is assigned to the AuthenticationManager.ChallengeHandler property. The challenge handler contains logic for obtaining the required credential for a server, either by providing hard-coded login information or prompting the user to enter it.
  • OAuth authorize handler - a component that implements the IOAuthAuthorizeHandler interface and is assigned to the AuthenticationManager.OAuthAuthorizeHandler property. The OAuth authorize handler contains logic that's specific to handling authorization using OAuth.
In some situations, you can use the default handlers and utility classes provided by ArcGIS Runtime SDK. If needed, you can also create custom handlers by implementing the required code.

A custom ChallengeHandler component can be created by defining a function to challenge for credentials with the signature: private async Task<Credential> ChallengeFunction(CredentialRequestInfo info). The following example shows a function with this signature that gets credentials from the user (by calling another function).

private async Task<Credential> Challenge(CredentialRequestInfo info)
{
    // Call code to get user credentials
    // Make sure it runs on the UI thread
    if (this.Dispatcher == null)
    {
        // No current dispatcher, code is already running on the UI thread
        return await GetUserCredentialsFromUI(info);
    }
    else
    {
        // Use the dispatcher to invoke the challenge UI
        return await this.Dispatcher.Invoke(() => GetUserCredentialsFromUI(info));
    }
}
To assign this function as the AuthenticationManager.ChallengeHandler, you can create a new Esri.ArcGISRuntime.Security.ChallengeHandler helper class (that implements IChallengeHandler) and pass in the function as an argument. The following example creates the challenge handler and assigns it to the authentication manager.
// Define a method to challenge the user for credentials when a secured resource is encountered
AuthenticationManager.Current.ChallengeHandler = new Esri.ArcGISRuntime.Security.ChallengeHandler(Challenge);

For a complete example of a challenge handler that prompts the user for a username and password, see the Token Challenge sample.

Add or remove credentials

The authentication manager maintains a collection of credentials, and the servers with which they are associated, for use by your app. You can add or remove credentials in this collection as needed. After successfully generating a credential, you must add it to the authentication manager's credential collection. Only credentials in the collection will be used to access secured resources.

The following example generates a new credential using login information entered by the user, then adds the credential to the authentication manager. Notice that the credential has an associated server URI.

try
{
    // exception is thrown here if a bad login is entered ...
    var cred = await Esri.ArcGISRuntime.Security.AuthenticationManager.Current.GenerateCredentialAsync(
        new Uri(PORTAL_SERVER_URL), UserTextBox.Text, PasswordTextBox.Password);

    // add the credential if it was generated successfully
    Esri.ArcGISRuntime.Security.AuthenticationManager.Current.AddCredential(cred);

    // connecting to the portal will use an available credential (based on the server URL)
    _portal = await Esri.ArcGISRuntime.Portal.ArcGISPortal.CreateAsync(new Uri(PORTAL_SERVER_URL));
}
catch(ArcGISWebException webExp)
{
    msg = "Could not log in. Please check credentials. Error code: " + webExp.Code;
}

Caution:

If the user name and password cannot be authenticated, an Esri.ArcGISRuntime.Http.ArcGISWebException is thrown. Make sure you handle such exceptions, as shown in the previous example, especially if you are getting login information from the user. One technique is to ignore such exceptions and connect anonymously (if supported by the server) when authentication fails.

If you no longer need the credential for a server in the authentication manager, you can remove it from the collection. This would be equivalent to signing out of a portal. The credential for a particular server can be found in the collection using the server URI.

The following example finds the credential for a server and removes it from the collection.

// find the credential for this server
Credential cred = Esri.ArcGISRuntime.Security.AuthenticationManager.Current.FindCredential(new Uri(PORTAL_SERVER_URL));

// remove it from the identity manager
Esri.ArcGISRuntime.Security.AuthenticationManager.Current.RemoveCredential(cred);

Work with the authentication manager

Authentication manager is a singleton class, which means there is always one for your ArcGIS Runtime app. It can be used to provide authentication for a variety of servers and authorization types because each server you register with authentication manager defines its authorization method. Depending on the authorization type for each server registered, different steps are required to configure authentication manager to challenge for the appropriate credentials. Authentication manager can also have only a single challenge handler associated with it.

ArcGIS Token authorization

For ArcGIS Token authorization, you do not usually need to register the server containing secured resources with authentication manager. If the location (URL) of the server or token endpoint is non-standard, however, you may need to register the server to ensure authentication manager can work with it as expected. In the server info for the registration, indicate the server URI and the token endpoint URI.

The following code registers a server that uses ArcGIS Token authorization.

private void RegisterMyTokenServer()
{
    // create a ServerInfo to describe the server and its authorization info
    ServerInfo tokenServerInfo = new ServerInfo
    {
        ServerUri = new Uri("http://my.server.com/"),
        TokenAuthenticationType = TokenAuthenticationType.ArcGISToken,
        TokenServiceUri = new Uri("https://my.server.com/get/some/tokens")
    };
    // register the server with AuthenticationManager
    AuthenticationManager.Current.RegisterServer(tokenServerInfo);
}

Challenge handler

To respond to a request for an ArcGIS Token secured resource, you need to have a challenge handler associated with authentication manager. If challenges are consistent — for example, they are always coming from ArcGIS token secured servers and always require a response that prompts the user for a login — your challenge handler can execute the same logic for each secure request. You may, however, have a variety of authorization types for secured resources and different ways of resolving each challenge. In that case, you may need a branching statement in your challenge handler to determine how credentials will be provided.

The following example shows a challenge handler that uses a hard-coded credential based on a known user (username and password). It checks the service URI to see if it's the expected resource and then provides credentials automatically without prompting the user. Additional logic is needed if challenges for other services are to be handled, such as prompting the user for a login. This method would be defined as the AuthenticationManager challenge handler using code like this: AuthenticationManager.Current.ChallengeHandler = new Esri.ArcGISRuntime.Security.ChallengeHandler(CreateKnownCredentials);

// Challenge method that checks for service access with known (hard coded) credentials
private async Task<Credential> CreateKnownCredentials(CredentialRequestInfo info)
{
    // If this isn't the expected resource, the credential will stay null
    Credential knownCredential = null;

    try
    {
        // Check the URL of the requested resource
        if (info.ServiceUri.AbsoluteUri.ToLower().Contains("usa_secure_user1"))
        {
            // Username and password are hard-coded for this resource
            // (Would be better to read them from a secure source)
            string username = "user1";
            string password = "user1";

            // Create a credential for this resource
            knownCredential = await AuthenticationManager.Current.GenerateCredentialAsync
                                    (info.ServiceUri,
                                        username,
                                        password,
                                        info.GenerateTokenOptions);
        }
        else
        {
            // ... perhaps prompt the user here if the username and password are not known ...
        }
    }
    catch (Exception ex)
    {
        // Report error accessing a secured resource
        _errorMsg = "Access to " + info.ServiceUri.AbsoluteUri + " denied. " + ex.Message;
    }

    // Return the credential
    return knownCredential;
}

Caution:

The preceding example provides a simple illustration of using hard-coded values for a known user. Including usernames and passwords in your code is obviously not a good practice. A better approach is to read them from a secure source, such as a secured web service, encrypted file, and so on.

OAuth authorization

Because OAuth authorization requires additional information about the server, you must register servers using OAuth authorization with the authentication manager. The following types of OAuth authorization methods (grants) are available:

  • Implicit: registration requires a client ID and a redirect URL. The user enters a login with the server and receives an access token.
  • Authorization code: registration requires a client ID, client secret, and a redirect URL. The user enters a login with the server and receives an access token and refresh token.
  • Client credentials: registration requires a client ID, client secret, and a redirect URL. The user does not need to enter a login, but rather is granted access on behalf of the app.

A description of the OAuth grant types is available at oauthlib.readthedocs.io.

The following example registers a server for OAuth with the authorization code grant. The variables ServerUrl, ClientId, ClientSecret, and RedirectUrl are string constants that have been defined earlier in the code.

// define server info for an OAuth (authorization code) server
var serverInfo = new ServerInfo
{
    ServerUri = new Uri(ServerUrl),
    TokenAuthenticationType = TokenAuthenticationType.OAuthAuthorizationCode,
    OAuthClientInfo = new OAuthClientInfo
    {
        ClientId = ClientId,
        ClientSecret = ClientSecret,
        RedirectUri = new Uri(RedirectUrl)
    }
};

// register the portal with authentication manager
AuthenticationManager.Current.RegisterServer(serverInfo);

Caution:

If using the Xamarin.Auth component in an Android or iOS app, the redirect URL for OAuth authorization must represent a valid endpoint. Arbitrary URLs, such as http://my.app.redirect or urn:ietf:wg:oauth:2.0:oob, for example, will return a 400 - Bad Request error. For iOS apps, all OAuth related URLs should be https.

Challenge handler

For OAuth authorization, authentication manager must have an associated challenge handler to respond to requests for secured resources on the server. The logic used in the challenge handler might differ in accordance with the OAuth grant type used (especially for a client credentials grant, in which the user does not need to provide a username and password). Usually, a challenge handler for OAuth will simply ask the authentication manager to generate a credential for the server, which will launch a login UI for the server (as described below).

The following example is a challenge handler method for a server using OAuth (either implicit or authorization code grant type). This method would be defined as the AuthenticationManager challenge handler using code like this: AuthenticationManager.Current.ChallengeHandler = new Esri.ArcGISRuntime.Security.ChallengeHandler(CreateCredentialAsync);

// ChallengeHandler function for AuthenticationManager, called when access to a secure resource is attempted
public async Task<Credential> CreateCredentialAsync(CredentialRequestInfo info)
{
    OAuthTokenCredential credential = null;
            
    try
    {
        // Create generate token options if necessary
        if (info.GenerateTokenOptions == null)
        {
            info.GenerateTokenOptions = new GenerateTokenOptions();
        }

        // Call GenerateCredentialAsync, pass in the server URI and token options
        // (AuthenticationManager will handle challenging the user for credentials)
        credential = await AuthenticationManager.Current.GenerateCredentialAsync
        (
            info.ServiceUri,
            info.GenerateTokenOptions
        ) as OAuthTokenCredential;
    }
    catch (Exception ex)
    {
        // Exception will be reported in calling function
        throw (ex);
    }

    // Return the credential (or null if authentication failed)
    return credential;
}
The call to AuthenticationManager.Current.GenerateCredentialAsync() in the previous code will cause authentication manager to show a UI to log in to the specified server, as described in the following section.

OAuth authorization handler

A request to generate credentials for a resource secured with OAuth causes the authentication manager to look for an OAuth authorization handler to show a login UI for the specified server. For some platforms (such as Universal Windows Platform), ArcGIS Runtime has a built-in component that serves as the OAuth authorization handler. On others (such as Windows Presentation Framework) you must create a custom component to present the login UI to the user and get an access token from the server.

An OAuth authorization handler is a class that implements the Esri.ArcGISRuntime.Security.IOAuthAuthorizeHandler interface. This interface defines a single method with the following signature.

// Function to handle authorization requests, takes URIs for the secured service, the authorization endpoint, and the redirect URI
public Task<IDictionary<string, string>> AuthorizeAsync(Uri serviceUri, Uri authorizeUri, Uri callbackUri)

The OAuth authorization handler shows the login UI (generated by the server that hosts secure content) in a web browser or control. When the user logs in successfully, the component is responsible for obtaining the authorization from the server. If the user cancels the login or closes the window without continuing, it should raise the appropriate exception.

To assign your custom IOAuthAuthorizeHandler class as the OAuth authorization handler, set a new instance of the class to the AuthenticationManager.Current.OAuthAuthorizeHandler property. For an example of a custom IOAuthAuthorizeHandler component to handle OAuth logins for a WPF app, see the OAuth security sample on GitHub.

HTTP (integrated Windows authentication) authorization

Using HTTP basic, HTTP digest or Integrated Windows Authentication (IWA) authorization, resources are protected by user name and password set on the service and prompted by browser popup or session cookie. When you use IWA, logins are managed through Microsoft Windows Active Directory. Users do not sign in and out of the portal website; instead, when they access resources, they are signed in using the same accounts they use to log in to Windows. A portal secured with HTTP authorization does not need to be registered with the authentication manager. A response from the server for a request for a secured resource will indicate the authorization mode implemented by the server.

When accessing an item secured with IWA on some platforms (such as Windows Presentation Framework), default credentials (the login that started the app, in other words) are automatically included and the user is never prompted to login. On other platforms such as Android, iOS, and Universal Windows Platform (UWP) credentials must be entered explicitly, either by prompting the user for them or by hard-coding them into the app.

The following example adds an ArcGISNetworkCredential with username, password, and domain values entered by the user to AuthenticationManager. NetworkUsername, NetworkPassword, and NetworkDomain are public variables that were defined earlier in the code (perhaps from a UI presented to the user on start up).

// Create a hard-coded network credential
ArcGISNetworkCredential hardcodedCredential = new ArcGISNetworkCredential
{
    Credentials = new System.Net.NetworkCredential(NetworkUsername, NetworkPassword, NetworkDomain),
    ServiceUri = new Uri(SecuredPortalUrl)
};

// Add the credential to the AuthenticationManager and report that a non-default credential is being used
AuthenticationManager.Current.AddCredential(hardcodedCredential);

Challenge handler

For platforms that provide a built-in mechanism for showing a UI for entering a login, a custom challenge handler is not required by the authentication manager. Likewise, for platforms that include the current Windows credential with requests for secured resources, you might be comfortable with assuming that authorized users will have access and no custom logic to show a login will be required. Otherwise, you will need a challenge handler that shows a login UI (controls for username, password, and domain), creates a credential, and adds it to the authentication manager. If the login is cancelled or unsuccessful, a null credential should be returned.

Note:

You must add the Private Networks capability to use IWA authentication in your UWP project. Add this capability by checking Private Networks (Client and Server) in your project's Package.appxmanifest file.

Public Key Infrastructure (PKI) authorization

Public Key Infrastructure (PKI) uses a mathematical technique called public key cryptography to generate the digital keys that represent a user or organization. ArcGIS for Server leverages the PKI solution with the IIS web server using the ArcGIS IIS Web Adaptor. When a request is made for a resource on ArcGIS for Server, the web server authenticates the user by validating a client certificate that contains the user's digital keys. The request (along with the user name) is then forwarded to ArcGIS for Server via the Web Adaptor. ArcGIS for Server verifies that the specified user has access to the requested resource before sending back the appropriate response. A portal secured with PKI authorization does not need to be registered with the authentication manager. A response from the server for a request for a secured resource will indicate the authorization mode implemented by the server.

Challenge handler

For platforms that provide a built-in mechanism for showing a UI for choosing a client certificate (such as Universal Windows Platform), a custom challenge handler is not required by the authentication manager. Otherwise, you need a challenge handler that shows a client certificate UI (a picker that shows available certificates) and creates a credential from it for use in the authentication manager. If the certificate choice is cancelled or unsuccessful, a null credential should be returned.

Note:

You must add the Private Networks capability to use Public Key Infrastructure (PKI) authentication in your UWP project. Add this capability by checking Private Networks (Client and Server) in your project's Package.appxmanifest file.