Access services with OAuth credentials (.NET MAUI)

Learn how to implement user authentication to access a secure ArcGIS service with OAuth credentials in a cross-platform app.

access services with oauth 2

You can use different types of authentication to access secured ArcGIS services. To implement OAuth credentials for user authentication, you can use your ArcGIS account to register an app with your portal and get a Client ID, and then configure your app to redirect users to login with their credentials when the service or content is accessed. This is known as user authentication. If the app uses premium ArcGIS Online services that consume credits, for example, the app user's account will be charged.

In this tutorial, you will build an app that implements user authentication using OAuth credentials so users can sign in and be authenticated through ArcGIS Online to access the ArcGIS World Traffic service.

Prerequisites

Before starting this tutorial:

Optionally, you may want to install the ArcGIS Maps SDK for .NET to get access to project templates in Visual Studio (Windows only) and offline copies of the NuGet packages.

Create OAuth credentials for user authentication

OAuth credentials are required to implement user authentication. These credentials are created and stored as an Application item in your organization's portal.

  1. Go to the Create OAuth credentials for user authentication tutorial and create OAuth credentials using your ArcGIS Location Platform or ArcGIS Online account.

  2. Copy the Client ID and Redirect URL as you will use them to implement user authentication later in this tutorial. The Client ID is found on the Application item's Overview page, while the Redirect URL is found on the Settings page.

Develop or download

You have two options for completing this tutorial:

  1. Option 1: Develop the code or
  2. Option 2: Download the completed solution

Option 1: Develop the code

Create a new Visual Studio Project

ArcGIS Maps SDK for .NET supports apps for Windows Presentation Framework (WPF), Universal Windows Platform (UWP), Windows UI Library (WinUI), and Multi-platform App UI (.NET MAUI). The instructions for this tutorial are specific to creating a .NET MAUI project using Visual Studio for Windows.

  1. Start Visual Studio and create a new project.

    • In the Visual Studio start screen, click Create a new project.
    • Choose the .NET MAUI App template for C#. If you don't see the template listed, you can find it by typing MAUI into the Search for templates text box.
    • Click Next.
    • Provide required values in the Configure your new project panel:
      • Project name: AccessServicesWithOAuth
      • Location: choose a folder
    • Click Next.
      • Choose the .NET 8 as framework you intend to target.
    • Click Create to create the project.

Add a reference to the API

  1. Add a reference to the API by installing a NuGet package.

    • In Solution Explorer, right-click Dependencies and choose Manage NuGet Packages.

    • In the NuGet Package Manager window, ensure the selected Package source is nuget.org (upper-right).

    • Select the Browse tab and search for ArcGIS Maps SDK.

    • In the search results, select the appropriate package for your platform. For this tutorial project, choose the Esri.ArcGISRuntime.Maui NuGet package.

    • Confirm the Latest stable version of the package is selected in the Version dropdown.

    • Click Apply.

    • The Preview Changes dialog confirms any package(s) dependencies or conflicts. Review the changes and click OK to continue installing the packages.

    • Review the license information on the License Acceptance dialog and click I Accept to add the package(s) to your project.

    • In the Visual Studio Output window, ensure the packages were successfully installed.

    • Close the NuGet Package Manager window.

Correct minimum OS versions

The .NET MAUI App template may have operating system (OS) requirements below what ArcGIS Maps SDK for .NET requires for a .NET MAUI app. You must modify the minimum OS versions in your .csproj to satisfy the ArcGIS Maps SDK for .NET requirements.

  1. In Visual Studio > Solution Explorer, double-click AccessServicesWithOAuth to open the .csproj.

  2. Modify the <SupportedOSPlatformVersion> properties in the <PropertyGroup> as shown below. This reflects the minimum OS requirements for ArcGIS Maps SDK for .NET MAUI for the current release.

    AccessServicesWithOAuth.csproj
    Expand
    Use dark colors for code blocks
    1
    2
    3
    4
    5
    6
    7
    8
    9
    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
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    		<!-- Versions -->
    		<ApplicationDisplayVersion>1.0</ApplicationDisplayVersion>
    		<ApplicationVersion>1</ApplicationVersion>
    
    		<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'">15.0</SupportedOSPlatformVersion>
    		<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'maccatalyst'">14.0</SupportedOSPlatformVersion>
    		<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'android'">26.0</SupportedOSPlatformVersion>
    
    		<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">10.0.19041.0</SupportedOSPlatformVersion>
    		<TargetPlatformMinVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">10.0.19041.0</TargetPlatformMinVersion>
    		<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'tizen'">6.5</SupportedOSPlatformVersion>
    
    Expand
  3. Save and close the .csproj file.

Set developer credentials

To allow your app users to access ArcGIS Location Services, use the developer credentials that you created in the Set up authentication step to authenticate requests for resources.

  1. From the Visual Studio Project menu, choose Add class .... Name the class ArcGISLoginPrompt.cs then click Add. The new class is added to your project and opens in Visual Studio.

  2. Select all the code in the new class and delete it.

  3. Copy all of the code below and paste it into the ArcGISLoginPrompt.cs class in your project.

    ArcGISLoginPrompt.cs
    Use dark colors for code blocksCopy
    1
    2
    3
    4
    5
    6
    7
    8
    9
    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
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    // Copyright 2022 Esri.
    //
    // Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
    // You may obtain a copy of the License at: http://www.apache.org/licenses/LICENSE-2.0
    //
    // Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an
    // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific
    // language governing permissions and limitations under the License.
    
    using Esri.ArcGISRuntime.Security;
    
    #if ANDROID
    
    using Android.App;
    using Application = Microsoft.Maui.Controls.Application;
    using Android.Content;
    using Android.Content.PM;
    
    #endif
    
    namespace UserAuth
    {
    
        internal static class ArcGISLoginPrompt
        {
            private const string ArcGISOnlineUrl = "https://www.arcgis.com/sharing/rest";
            // Specify the Client ID and Redirect URL to use with OAuth authentication.
            // See the instructions here for creating OAuth app settings:
            // https://developers.arcgis.com/documentation/security-and-authentication/user-authentication/tutorials/create-oauth-credentials-user-auth/
    
            private const string AppClientId = "YOUR_CLIENT_ID";
            private const string OAuthRedirectUrl = "YOUR_REDIRECT_URL";
    
            public static async Task<bool> EnsureAGOLCredentialAsync()
            {
                bool loggedIn = false;
    
                try
                {
                    // Create a challenge request for portal credentials (OAuth credential request for arcgis.com)
                    CredentialRequestInfo challengeRequest = new CredentialRequestInfo
                    {
                        // Use the OAuth authorization code workflow.
                        GenerateTokenOptions = new GenerateTokenOptions
                        {
                            TokenAuthenticationType = TokenAuthenticationType.OAuthAuthorizationCode
                        },
    
                        // Indicate the url (portal) to authenticate with (ArcGIS Online)
                        ServiceUri = new Uri(ArcGISOnlineUrl)
                    };
    
                    // Call GetCredentialAsync on the AuthenticationManager to invoke the challenge handler
                    Credential cred = await AuthenticationManager.Current.GetCredentialAsync(challengeRequest, false);
                    loggedIn = cred != null;
                }
                catch (OperationCanceledException)
                {
                    // OAuth login was canceled, no need to display error to user.
                }
                catch (Exception ex)
                {
                    await Application.Current.MainPage.DisplayAlert("Login failed", ex.Message, "OK");
                }
    
                return loggedIn;
            }
    
            public static void SetChallengeHandler()
            {
                var userConfig = new OAuthUserConfiguration(new Uri(ArcGISOnlineUrl), AppClientId, new Uri(OAuthRedirectUrl));
                AuthenticationManager.Current.OAuthUserConfigurations.Add(userConfig);
                AuthenticationManager.Current.OAuthAuthorizeHandler = new OAuthAuthorize();
            }
        }
    
        #region IOAuthAuthorizationHandler implementation
    
        public class OAuthAuthorize : IOAuthAuthorizeHandler
        {
    #if IOS || MACCATALYST
            TaskCompletionSource<IDictionary<string, string>> _taskCompletionSource;
    
            public Task<IDictionary<string, string>> AuthorizeAsync(Uri serviceUri, Uri authorizeUri, Uri callbackUri)
            {
                _taskCompletionSource = new TaskCompletionSource<IDictionary<string, string>>();
                Microsoft.Maui.ApplicationModel.MainThread.BeginInvokeOnMainThread(async () =>
                {
                    try
                    {
                        var result = await WebAuthenticator.AuthenticateAsync(authorizeUri, callbackUri);
                        _taskCompletionSource.TrySetResult(result.Properties);
                    }
                    catch (Exception ex)
                    {
                        _taskCompletionSource.TrySetException(ex);
                    }
                });
                return _taskCompletionSource.Task;
            }
    #elif ANDROID
            public async Task<IDictionary<string, string>> AuthorizeAsync(Uri serviceUri, Uri authorizeUri, Uri callbackUri)
            {
                var result = await WebAuthenticator.AuthenticateAsync(authorizeUri, callbackUri);
                return result.Properties;
            }
    #elif WINDOWS
            public async Task<IDictionary<string, string>> AuthorizeAsync(Uri serviceUri, Uri authorizeUri, Uri callbackUri)
            {
                var result = await WinUIEx.WebAuthenticator.AuthenticateAsync(authorizeUri, callbackUri);
                return result.Properties;
            }
    #else
            public async Task<IDictionary<string, string>> AuthorizeAsync(Uri serviceUri, Uri authorizeUri, Uri callbackUri)
            {
                throw new NotImplementedException();
            }
    #endif
        }
    
    #if ANDROID
    
        [Activity(NoHistory = true, Exported = true, LaunchMode = LaunchMode.SingleTop)]
        [IntentFilter(new[] { Intent.ActionView },
           Categories = new[] { Intent.CategoryDefault, Intent.CategoryBrowsable },
           DataScheme = "my-app", DataHost = "auth")]
        public class WebAuthenticationCallbackActivity : WebAuthenticatorCallbackActivity
        {
        }
    
    #endif
    
        #endregion IOAuthAuthorizationHandler implementation
    }
  4. Add your values for the client ID (AppClientId) and for the redirect URL (OAuthRedirectUrl). These are the user authentication settings you created in the Set up authentication step.

    ArcGISLoginPrompt.cs
    Use dark colors for code blocks
    1
    2
    3
    4
    5
    6
    7
    8
    9
    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
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
        internal static class ArcGISLoginPrompt
        {
            private const string ArcGISOnlineUrl = "https://www.arcgis.com/sharing/rest";
            // Specify the Client ID and Redirect URL to use with OAuth authentication.
            // See the instructions here for creating OAuth app settings:
            // https://developers.arcgis.com/documentation/security-and-authentication/user-authentication/tutorials/create-oauth-credentials-user-auth/
    
            private const string AppClientId = "YOUR_CLIENT_ID";
            private const string OAuthRedirectUrl = "YOUR_REDIRECT_URL";
    
  5. Save and close the ArcGISLoginPrompt.cs file.

  6. In the Solution Explorer, open MauiProgram.cs by double-clicking.

  7. Add the following required using directives at the top of the file.

    MauiProgram.cs
    Expand
    Use dark colors for code blocks
    1
    2
    3
    4
    5
    6
    7
    8
    9
    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
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    namespace DisplayAMap;
    
    using Esri.ArcGISRuntime;
    using Esri.ArcGISRuntime.Maui;
    
    using Microsoft.Extensions.Logging;
    
    public static class MauiProgram
    {
        public static MauiApp CreateMauiApp()
        {
    
    Expand
  8. In the CreateMauiApp() function, below the code that creates the MauiAppBuilder, call UseArcGISRuntime on the builder variable. Also add a line to set the OAuth challenge handler (defined in the static ArcGISLoginPrompt class).

    MauiProgram.cs
    Expand
    Use dark colors for code blocks
    1
    2
    3
    4
    5
    6
    7
    8
    9
    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
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
            var builder = MauiApp.CreateBuilder();
    		builder
    			.UseMauiApp<App>()
    			.ConfigureFonts(fonts =>
    			{
    				fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
    				fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
                });
    
            builder.UseArcGISRuntime(config =>
            {
    
            });
    
            // Set up the AuthenticationManager to use OAuth for secure ArcGIS Online requests.
            UserAuth.ArcGISLoginPrompt.SetChallengeHandler();
    
    #if DEBUG
            builder.Logging.AddDebug();
    #endif
    
    Expand
  9. Save and close the MauiProgram.cs file.

    Best Practice: The OAuth credentials are stored directly in the code as a convenience for this tutorial. Do not store credentials directly in source code in a production environment.

  10. Follow the steps below to set up the .NET MAUI WebAuthenticator for the desired platform(s). Note that these configuration settings assume your redirect URL begins with my-app://. The .NET MAUI WebAuthenticator helps you implement browser-based authentication flows, which listen for a callback to a specific URL registered to the app.

Add a traffic layer

You will add a layer to display the ArcGIS World Traffic service, a dynamic map service that presents historical and near real-time traffic information for different regions in the world. This is a secure service and requires an ArcGIS Online organizational subscription.

  1. In the Visual Studio > Solution Explorer, double-click MapViewModel.cs to open the file.

  2. In the SetupMap() function, update the line that sets the Map property for the view model to instead store the map in a variable. Also change the line that sets the map's initial extent to use the variable.

    MapViewModel.cs
    Use dark colors for code blocks
    1
    2
    3
    4
    5
    6
    7
    8
    9
    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
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
            private void SetupMap()
            {
    
                // Create a new map with a 'topographic vector' basemap.
                var trafficMap = new Map(BasemapStyle.ArcGISTopographic);
    
                var mapCenterPoint = new MapPoint(-118.805, 34.027, SpatialReferences.Wgs84);
    
                trafficMap.InitialViewpoint = new Viewpoint(mapCenterPoint, 100000);
    
            }
    
  3. Create an ArcGISMapImageLayer to display the traffic service and add it to the map's collection of data layers (operational layers).

    MapViewModel.cs
    Use dark colors for code blocks
    1
    2
    3
    4
    5
    6
    7
    8
    9
    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
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
            private void SetupMap()
            {
    
                // Create a new map with a 'topographic vector' basemap.
                var trafficMap = new Map(BasemapStyle.ArcGISTopographic);
    
                var mapCenterPoint = new MapPoint(-118.805, 34.027, SpatialReferences.Wgs84);
    
                trafficMap.InitialViewpoint = new Viewpoint(mapCenterPoint, 100000);
    
                // Create a layer to display the ArcGIS World Traffic service.
                var trafficServiceUrl = "https://traffic.arcgis.com/arcgis/rest/services/World/Traffic/MapServer";
                var trafficLayer = new ArcGISMapImageLayer(new Uri(trafficServiceUrl));
    
                // Add the traffic layer to the map's data layer collection.
                trafficMap.OperationalLayers.Add(trafficLayer);
    
            }
    
  4. Set the view model's Map property. Data binding handles displaying the map in the view.

    MapViewModel.cs
    Use dark colors for code blocks
    1
    2
    3
    4
    5
    6
    7
    8
    9
    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
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
            private void SetupMap()
            {
    
                // Create a new map with a 'topographic vector' basemap.
                var trafficMap = new Map(BasemapStyle.ArcGISTopographic);
    
                var mapCenterPoint = new MapPoint(-118.805, 34.027, SpatialReferences.Wgs84);
    
                trafficMap.InitialViewpoint = new Viewpoint(mapCenterPoint, 100000);
    
                // Create a layer to display the ArcGIS World Traffic service.
                var trafficServiceUrl = "https://traffic.arcgis.com/arcgis/rest/services/World/Traffic/MapServer";
                var trafficLayer = new ArcGISMapImageLayer(new Uri(trafficServiceUrl));
    
                // Add the traffic layer to the map's data layer collection.
                trafficMap.OperationalLayers.Add(trafficLayer);
    
                // Set the view model Map property with the new map.
                this.Map = trafficMap;
    
            }
    

Run the app

Click Debug > Start Debugging (or press <F5> on the keyboard) to run the app.

You will be prompted for a username and password. Once you authenticate successfully, you will see a traffic map centered on the Santa Monica Mountains in California.

ArcGIS World Traffic service layer

Alternatively, you can download the tutorial solution, as follows.

Option 2: Download the solution

  1. Click the Download solution link in the right-hand panel of the page.

  2. Unzip the file to a location on your machine.

  3. Open the .sln file in Visual Studio.

Since the downloaded solution does not contain authentication credentials, you must add the developer credentials that you created in the set up authentication section.

Set developer credentials in the solution

To allow your app users to access ArcGIS location services, use the developer credentials that you created in the Set up authentication step to authenticate requests for resources.

  1. From the Visual Studio Solution explorer window, open the ArcGISLoginPrompt.cs file.

  2. Set your values for the client ID (OAuthClientID) and the redirect URL (OAuthRedirectUrl). These are the user authentication settings you created in the Set up authentication step.

    ArcGISLoginPrompt.cs
    Use dark colors for code blocks
    1
    2
    3
    4
    5
    6
    7
    8
    9
    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
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
        internal static class ArcGISLoginPrompt
        {
            private const string ArcGISOnlineUrl = "https://www.arcgis.com/sharing/rest";
            // Specify the Client ID and Redirect URL to use with OAuth authentication.
            // See the instructions here for creating OAuth app settings:
            // https://developers.arcgis.com/documentation/security-and-authentication/user-authentication/tutorials/create-oauth-credentials-user-auth/
    
            private const string AppClientId = "YOUR_CLIENT_ID";
            private const string OAuthRedirectUrl = "YOUR_REDIRECT_URL";
    

Best Practice: The OAuth credentials are stored directly in the code as a convenience for this tutorial. Do not store credentials directly in source code in a production environment.

Run the app

Click Debug > Start Debugging (or press <F5> on the keyboard) to run the app.

You will be prompted for a username and password. Once you authenticate successfully, you will see a traffic map centered on the Santa Monica Mountains in California.

ArcGIS World Traffic service layer

Additional resources

If you are implementing OAuth for another .NET platform, you might find some of the following resources helpful.

  • ArcGIS Maps SDK for .NET OAuth sample: The WPF version of this sample uses code similar to code used in this tutorial. The sample is available for other .NET platforms (use the switcher control at the top of the page) to illustrate implementing OAuth for apps targeting WinUI, UWP, and .NET MAUI.
  • Web authentication broker: Use this authentication broker to implement OAuth in your Universal Windows Platform (UWP) apps.

Your browser is no longer supported. Please upgrade your browser for the best experience. See our browser deprecation post for more details.