Access services with OAuth 2.0

Learn how to authenticate a user to access a secure ArcGIS service with OAuth 2.0.

access services with oauth 2

In this tutorial, you will build an app that uses named user login credentials to access a secure ArcGIS service using OAuth 2.0.

You can use different types of authentication to access ArcGIS location services. To implement OAuth 2.0, you can use your ArcGIS account to register an application 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 services that consume credits, the app user's account will be charged.

You will implement OAuth 2.0 so users can sign in to ArcGIS to access the ArcGIS World Traffic service.

Prerequisites

The following is required for this tutorial:

  1. Your system meets the system requirements.

Steps

Configure OAuth 2.0 for your app

Use the ArcGIS Developer dashboard to register your app, generate a client ID, and set a redirect URL to access the secure service.

  1. Sign in to your ArcGIS developer account. If you don't already have one, sign-up for free. You need to sign in so you can create an application and get a client ID for authentication.

  2. Click the OAuth 2.0 tab in the ribbon at the top.

  3. Click the New Application button in the upper-left of the page.

  4. In the Create New Application window, provide a Title and an optional Description for your app and click Create application. When the application is created, it will have a Client ID, a Client Secret, and a Temporary Token property you can view.

  5. Click the Add URI button at the bottom of the page to add a redirect URL.

  6. In the Add Allowed URI window, enter a redirect URI and click Add.

    You'll use the Client ID and the redirect URL in your iOS app.

Open the Xcode project

  1. To start the tutorial, complete the Display a map tutorial or download and unzip the solution.

  2. Open the .xcodeproj file in Xcode.

Remove API keywords

An API Key is not required for this app because you are implementing authentication using OAuth 2.0.

  1. Open MainApp.swift and remove the line that sets the API key.

    MainApp.swift
    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
    import SwiftUI
    
    import ArcGIS
    
    @main
    struct MainApp: App {
    
        init() {
            ArcGISEnvironment.apiKey = APIKey("<#your-API-key#>")
        }
    
        var body: some SwiftUI.Scene {
            WindowGroup {
                ContentView()
    
                    .ignoresSafeArea()
    
            }
        }
    
    }

Add a layer to map

Add the World Traffic layer to the map and test run the app.

  1. Open ContentView.swift and update the existing map variable to add a traffic layer to the map's operational layers collection.

    ContentView.swift
    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
    struct ContentView: View {
    
        @State private var map = {
            let map = Map(basemapStyle: .arcGISTopographic)
            map.initialViewpoint = Viewpoint(latitude: 34.02700, longitude: -118.80500, scale: 72_000)
    
            let trafficLayerURL = URL(string: "http://www.arcgis.com/home/item.html?id=bbdcd78953e5439985004023c8eda03d")!
            let trafficLayer = ArcGISMapImageLayer(url: trafficLayerURL)
            map.addOperationalLayer(trafficLayer)
    
            return map
        }()
    
        var body: some View {
            MapView(map: map)
    
        }
    
    }
    
  2. Press Command+R to run the app.

Note that the basemap and traffic layer do not load into the map because they both require authentication. Let's integrate OAuth authentication into the app.

Integrate OAuth 2.0 into your app

Create an ArcGISAuthenticationChallengeHandler that handles OAuth authentication every time an ArcGIS resource is accessed.

  1. Create a final class named MyArcGISChallengeHandler of type ArcGISAuthenticationChallengeHandler and tag it as the @MainActor. Initialize the challenge handler with an array of OAuthUserConfiguration.

    ContentView.swift
    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
    import SwiftUI
    
    import ArcGIS
    
    struct ContentView: View {
    
        @State private var map = {
            let map = Map(basemapStyle: .arcGISTopographic)
            map.initialViewpoint = Viewpoint(latitude: 34.02700, longitude: -118.80500, scale: 72_000)
    
            let trafficLayerURL = URL(string: "http://www.arcgis.com/home/item.html?id=bbdcd78953e5439985004023c8eda03d")!
            let trafficLayer = ArcGISMapImageLayer(url: trafficLayerURL)
            map.addOperationalLayer(trafficLayer)
    
            return map
        }()
    
        var body: some View {
            MapView(map: map)
    
        }
    
    }
    
    // Creates an ArcGIS authentication challenge handler.
    @MainActor
    final class MyArcGISChallengeHandler: ObservableObject, ArcGISAuthenticationChallengeHandler {
        // The OAuth configurations that this challenge handler can work with.
        let oAuthUserConfigurations: [OAuthUserConfiguration]
        public init(
            oAuthUserConfigurations: [OAuthUserConfiguration] = []
        ) {
            self.oAuthUserConfigurations = oAuthUserConfigurations
        }
    
    }
  2. Add a new function named handleArcGISAuthenticationChallenge(_:) to handle the authentication challenge. This function attempts to create an OAuthUserCredential using the credentials provided by the first OAuthUserConfiguration in the array. The credentials are stored in the in-memory credential store.

    ContentView.swift
    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
    // Creates an ArcGIS authentication challenge handler.
    @MainActor
    final class MyArcGISChallengeHandler: ObservableObject, ArcGISAuthenticationChallengeHandler {
        // The OAuth configurations that this challenge handler can work with.
        let oAuthUserConfigurations: [OAuthUserConfiguration]
        public init(
            oAuthUserConfigurations: [OAuthUserConfiguration] = []
        ) {
            self.oAuthUserConfigurations = oAuthUserConfigurations
        }
    
        // Handles the challenge to an ArcGIS secured resource that requires OAuth or ArcGIS Token authentication.
        func handleArcGISAuthenticationChallenge(
            _ challenge: ArcGISAuthenticationChallenge
        ) async throws -> ArcGISAuthenticationChallenge.Disposition {
            // If an OAuth user configuration is available for the challenge then create an `OAuthUserCredential`.
            if let configuration = oAuthUserConfigurations.first(where: { $0.canBeUsed(for: challenge.requestURL) }) {
                return .continueWithCredential(
                    try await OAuthUserCredential.credential(for: configuration)
                )
            } else {
                // If not, prompt the user for a username and password to create a `TokenCredential`.
                // ...
                return .continueWithCredential(
                    try await TokenCredential.credential(for: challenge, username: "username", password: "password")
                )
            }
        }
    
    }
  3. Create a @StateObject variable in ContentView named myArcGISChallengeHandler that creates an instance of the MyArcGISChallengeHandler class with the portal URL, client ID, and redirect URL. The client ID and redirect URL are values that you created in the previous step, Configure OAuth 2.0 for your app.

    ContentView.swift
    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
    struct ContentView: View {
    
        /// `clientID` is a unique identifier made for a public application created by the ArcGIS Maps SDK team.
        /// `redirectURL` is the redirect URL registered with the clientID.
        /// - Note: The clientID and redirectURL values here are examples. You must register your own app, generate a client ID, and set a redirect URL to access secure services in your deployed app.
        @StateObject private var myArcGISChallengeHandler = MyArcGISChallengeHandler(
            oAuthUserConfigurations: [
                OAuthUserConfiguration(
                    portalURL: URL(string: "https://www.arcgis.com")!,
                    clientID: "lgAdHkYZYlwwfAhC",
                    redirectURL: URL(string: "my-ags-app://auth")!
                )
            ]
        )
    
        @State private var map = {
            let map = Map(basemapStyle: .arcGISTopographic)
            map.initialViewpoint = Viewpoint(latitude: 34.02700, longitude: -118.80500, scale: 72_000)
    
            let trafficLayerURL = URL(string: "http://www.arcgis.com/home/item.html?id=bbdcd78953e5439985004023c8eda03d")!
            let trafficLayer = ArcGISMapImageLayer(url: trafficLayerURL)
            map.addOperationalLayer(trafficLayer)
    
            return map
        }()
    
        var body: some View {
            MapView(map: map)
    
        }
    
    }
    
  4. Lastly, add an .onAppear modifier to the map view and assign myArcGISChallengeHandler to the ArcGISAuthenticationChallengeHandler that is provided by the app's ArcGISEnvironment.authenticationManager.

    ContentView.swift
    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
    78
    79
    80
    81
    82
    83
    84
    85
    86
    struct ContentView: View {
    
        /// `clientID` is a unique identifier made for a public application created by the ArcGIS Maps SDK team.
        /// `redirectURL` is the redirect URL registered with the clientID.
        /// - Note: The clientID and redirectURL values here are examples. You must register your own app, generate a client ID, and set a redirect URL to access secure services in your deployed app.
        @StateObject private var myArcGISChallengeHandler = MyArcGISChallengeHandler(
            oAuthUserConfigurations: [
                OAuthUserConfiguration(
                    portalURL: URL(string: "https://www.arcgis.com")!,
                    clientID: "lgAdHkYZYlwwfAhC",
                    redirectURL: URL(string: "my-ags-app://auth")!
                )
            ]
        )
    
        @State private var map = {
            let map = Map(basemapStyle: .arcGISTopographic)
            map.initialViewpoint = Viewpoint(latitude: 34.02700, longitude: -118.80500, scale: 72_000)
    
            let trafficLayerURL = URL(string: "http://www.arcgis.com/home/item.html?id=bbdcd78953e5439985004023c8eda03d")!
            let trafficLayer = ArcGISMapImageLayer(url: trafficLayerURL)
            map.addOperationalLayer(trafficLayer)
    
            return map
        }()
    
        var body: some View {
            MapView(map: map)
    
                .onAppear {
                    ArcGISEnvironment.authenticationManager.arcGISAuthenticationChallengeHandler = myArcGISChallengeHandler
                }
    
        }
    
    }
    
    Expand
  5. Press Command + R to run the app.

Upon app launch, you will be prompted to log in with your ArcGIS Developer credentials. Once you authenticate successfully with ArcGIS Online, the basemap and traffic layer will appear in the map.

What's next?

Learn how to use additional API features, ArcGIS location services, and ArcGIS tools in these tutorials:

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