ArcGIS token challenge

View inAndroidFormsUWPWPFWinUIiOSView on GitHubSample viewer app

This sample demonstrates how to prompt the user for a username and password to authenticate with ArcGIS Server to access an ArcGIS token-secured service. Accessing secured services requires a login that's been defined on the server.

Image of ArcGIS token challenge

Use case

Your app may need to access services that are restricted to authorized users. For example, your organization may host ArcGIS services that are only accessible by verified users.

How to use the sample

When you run the sample, the app will load a map that contains a layer from a secured service. Then, you will be challenged for a user name and password to view that layer. Enter the correct user name (user1) and password (user1). If you authenticate successfully, the secured layer will display, otherwise the map will contain only the public layers.

How it works

  1. A custom ChallengeHandler is set for AuthenticationManager that displays a login dialog for entering a username and password.
  2. In response to the attempt to access secured content, the AuthenticationManager calls the challenge handler.
  3. A TokenCredential is created from the entered username and password, and an attempt is made to load the layer.

Relevant API

  • AuthenticationManager
  • TokenCredential

Additional information

Please note: the username and password are case sensitive for token-based authentication. If the user doesn't have permission to access all the content within the portal item, partial or no content will be returned.

Tags

authentication, cloud, portal, remember, security

Sample Code

TokenSecuredChallenge.xamlTokenSecuredChallenge.xamlTokenSecuredChallenge.xaml.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
135
136
137
138
139
140
141
142
143
144
145
146
<UserControl x:Class="ArcGISRuntime.WPF.Samples.TokenSecuredChallenge.TokenSecuredChallenge"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:esri="http://schemas.esri.com/arcgis/runtime/2013"
             xmlns:mapping="clr-namespace:Esri.ArcGISRuntime.Mapping;assembly=Esri.ArcGISRuntime">
    <Grid x:Name="layoutGrid">
        <esri:MapView x:Name="MyMapView">
            <mapping:Map>
                <mapping:Map.OperationalLayers>
                    <!--  This layer is public and does not require credentials  -->
                    <mapping:ArcGISTiledLayer Name="World Street Map - Public" Source="https://services.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer" />
                    <!--  This layer is secured with ArcGIS tokens and requires a login  -->
                    <!--  username: user1 | password: user1  -->
                    <mapping:ArcGISMapImageLayer Name="USA - Secure" Source="https://sampleserver6.arcgisonline.com/arcgis/rest/services/USA_secure_user1/MapServer" />
                </mapping:Map.OperationalLayers>
            </mapping:Map>
        </esri:MapView>

        <!--  Layer listing with status  -->
        <Border Style="{StaticResource BorderStyle}">
            <StackPanel>
                <TextBlock Margin="4"
                           FontSize="14"
                           FontWeight="Bold"
                           Text="Map layers (with status)" />
                <ListView x:Name="listLayerStatus"
                          Padding="6"
                          ItemsSource="{Binding ElementName=MyMapView, Path=Map.AllLayers}">
                    <ListView.ItemTemplate>
                        <DataTemplate>
                            <StackPanel>
                                <TextBlock HorizontalAlignment="Left" Text="{Binding Name}" />
                                <StackPanel Orientation="Horizontal">
                                    <TextBlock Margin="20,0,0,5" FontWeight="Bold">
                                        <TextBlock.Style>
                                            <Style TargetType="{x:Type TextBlock}">
                                                <Style.Triggers>
                                                    <DataTrigger Binding="{Binding LoadStatus}" Value="2">
                                                        <Setter Property="Foreground" Value="Red" />
                                                        <Setter Property="Text" Value="Access Denied" />
                                                    </DataTrigger>
                                                    <DataTrigger Binding="{Binding LoadStatus}" Value="0">
                                                        <Setter Property="Foreground" Value="Green" />
                                                        <Setter Property="Text" Value="Access Granted" />
                                                    </DataTrigger>
                                                </Style.Triggers>

                                                <Style.Setters>
                                                    <Setter Property="Foreground" Value="Black" />
                                                    <Setter Property="Text" Value="Initializing" />
                                                </Style.Setters>
                                            </Style>
                                        </TextBlock.Style>
                                    </TextBlock>
                                </StackPanel>
                            </StackPanel>
                        </DataTemplate>
                    </ListView.ItemTemplate>
                </ListView>
            </StackPanel>
        </Border>

        <!--  Login UI  -->
        <Border x:Name="loginPanel"
                HorizontalAlignment="Left"
                Style="{StaticResource BorderStyle}"
                Visibility="Collapsed">
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="Auto" />
                    <ColumnDefinition Width="*" />
                </Grid.ColumnDefinitions>
                <Grid.RowDefinitions>
                    <RowDefinition Height="*" />
                    <RowDefinition Height="Auto" />
                    <RowDefinition Height="Auto" />
                    <RowDefinition Height="Auto" />
                    <RowDefinition Height="Auto" />
                    <RowDefinition Height="*" />
                </Grid.RowDefinitions>

                <TextBlock Grid.Row="0"
                           Grid.Column="0"
                           Grid.ColumnSpan="2"
                           Margin="0,0,0,8"
                           Text="{Binding ServiceUrl, StringFormat='Login to: {0}'}"
                           TextWrapping="Wrap" />
                <TextBlock Grid.Row="1"
                           Grid.Column="0"
                           Grid.ColumnSpan="2"
                           Margin="0,0,0,8"
                           FontWeight="SemiBold"
                           Text="Username and password are user1/user1"
                           TextWrapping="Wrap" />
                <TextBlock Grid.Row="2"
                           Grid.Column="0"
                           Margin="2"
                           VerticalAlignment="Center"
                           Text="Username" />
                <TextBox Grid.Row="2"
                         Grid.Column="1"
                         Margin="2"
                         Text="{Binding UserName, UpdateSourceTrigger=PropertyChanged}" />
                <TextBlock Grid.Row="3"
                           Grid.Column="0"
                           Margin="2"
                           VerticalAlignment="Center"
                           Text="Password" />
                <!--
                    For simplicity, the password is visible in this example. You can use a PasswordBox to mask the password text,
                    but it complicates data binding. See this discussion for details: http://stackoverflow.com/questions/1483892/how-to-bind-to-a-passwordbox-in-mvvm
                -->
                <TextBox Grid.Row="3"
                         Grid.Column="1"
                         Margin="2"
                         Text="{Binding Password, UpdateSourceTrigger=PropertyChanged}" />
                <Button Grid.Row="4"
                        Grid.Column="0"
                        Grid.ColumnSpan="2"
                        Margin="0,12,0,0"
                        Padding="5,2.5,5,2.5"
                        HorizontalAlignment="Center"
                        Click="LoginButtonClick"
                        Content="Login and load layer"
                        IsDefault="True" />
                <TextBlock Grid.Row="5"
                           Grid.Column="0"
                           Grid.ColumnSpan="2"
                           Margin="8,12,8,0"
                           Foreground="Red"
                           Text="{Binding ErrorMessage}"
                           TextWrapping="Wrap">
                    <TextBlock.Style>
                        <Style TargetType="{x:Type TextBlock}">
                            <Style.Triggers>
                                <DataTrigger Binding="{Binding ErrorMessage}" Value="">
                                    <Setter Property="Visibility" Value="Collapsed" />
                                </DataTrigger>
                            </Style.Triggers>
                        </Style>
                    </TextBlock.Style>
                </TextBlock>
            </Grid>
        </Border>
    </Grid>
</UserControl>

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