Configure OAuth 2.0 (C++ API)

Learn how configure OAuth 2.0 and load private layers. Your app may need to access items in the ArcGIS Platform that are only shared with authorized users. For example, your organization may host private data layers that are only accessible to verified users. You can use an ArcGIS Identity to allow individual users to authorize your app to use the content and services to which the user has been granted access.

In this tutorial, you will learn how to include an OAuth 2.0 challenge handler initializer in your C++ API level. For the challenge handler, you will use the sample OAuth challenge handler header file and C++ file in the following folder. For your own application, you may create your own OAuth challenge handler according to your requirements.

Use dark colors for code blocksCopy
 
1
Plugins\ArcGISMapsSDK\Source\ArcGISSamples\Private\Security

Prerequisites

Before starting this tutorial, you should:

  1. Have an ArcGIS account, and have a set of Client ID and Redirect URI for your ArcGIS identity to access a private layer. If you don't have an account, sign up for free.
  2. Ensure your development environment meets the system requirements.
  3. Take Install and setup steps, and create a new project, and choose the C++ API as your scene setting option.

Steps

In this tutorial you'll be setting up OAuth 2.0 by using sample OAuth source code that used for the Modes Panel UI.

You can find a sample header file in:

Use dark colors for code blocksCopy
 
1
Plugins\ArcGISMapsSDK\Source\ArcGISSamples\Public\SampleCppOAuth.h

And a sample C++ file in:

Use dark colors for code blocksCopy
 
1
Plugins\ArcGISMapsSDK\Source\ArcGISSamples\Private\SampleCppOAuth.cpp

Initialize the API

  1. Click on File on the Menu Bar and select New Level.

  2. Select Empty Level in the popup window.

    New Level

  3. To create these scripts in your project, you need to go to the content folder. Click Tools > New C++ Class.

  4. This will show the Choose Parent Class wizard. You want your script to attach to an Actor. Select All Classes and click on ArcGIS Actor under Actor, then click Next. ArcGIS Actor includes ArcGIS Maps SDK Subsystem Listener that allows you to use the editor mode.

    Choose Parent Class

  5. Name the Actor CppOAuth and set where you like to place the Actor script. It can be set in the host project or in a different module. The Public/Private button will define whether this class will be public or private. Also, you can define the path where the file will be. After you fill out the parameters click Create Class.

  6. After Unreal Engine compiles the project, Visual Studio will automatically open the .h and the .cpp files.

Set up the project

Before working on the .h and the .cpp files, we will first set up the project.

  1. Navigate to your .cpp file folder. Create a PCH file with the .h suffix as follows:

    Use dark colors for code blocksCopy
              
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    #pragma once
    
    #include <assert.h>
    #include <atomic>
    #include <functional>
    #include <memory>
    
    #include "CoreMinimal.h"
    
    #include "ArcGISMapsSDK/API/Unreal/Dictionary.h"
  2. Open your_project_file.Build.cs file.

  3. Add this line of code after PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs; that points to your PCH file.

    Use dark colors for code blocksCopy
     
    1
    PrivatePCHHeaderFile = "Private/your_PCH_file.h";
  4. In PublicDependencyModuleNames.AddRange, add two modules as follows:

    Use dark colors for code blocksCopy
     
    1
    PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore" , "ArcGISMapsSDK","ArcGISSamples"});

Create header file

  1. Review the header file and make sure you have the following includes.

    Use dark colors for code blocksCopy
       
    1
    2
    3
    #include "CoreMinimal.h"
    #include "ArcGISMapsSDK/Actors/ArcGISActor.h"
    #include "CppOAuth.generated.h"
  2. Set the default values for the Actor's properties and set it to public.

    Use dark colors for code blocksCopy
     
    1
    ACppOAuth();
  3. Create a class to trigger the OAuth challenge handler when you set add private service and its configuration in the Details panel during the editor time. In this tutorial, you name it PostEditChangeProperty.

    Use dark colors for code blocksCopy
       
    1
    2
    3
    #if WITH_EDITOR
        void PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) override;
    #endif
  4. For the editor mode to react to changes during the editor time, add subsystem listener for the ArcGIS Map View Actor which is connected to the subsystem.

    Use dark colors for code blocksCopy
     
    1
    void OnArcGISMapViewChanged(AArcGISMapView* InArcGISMapView) override;
  5. Add a property to select the MapType in the Details panel under ArcGISMaps SDK > MyCPPOAuth category and set it to protected. For the information about properties, see Unreal Engine documentation.

    Use dark colors for code blocksCopy
      
    1
    2
    UPROPERTY(EditAnywhere, Category = "ArcGISMapsSDK|MyCppOAuth")
        TEnumAsByte<EArcGISMapType::Type> MapType;
    
  6. Add properties for ClientID, RedirectURI, and ServiceURL to select them from the details panel under the same category.

    Use dark colors for code blocksCopy
            
    1
    2
    3
    4
    5
    6
    7
    8
    UPROPERTY(EditAnywhere, Category = "ArcGISMapsSDK|MyCppOAuth")
        FString ClientID;
    
    UPROPERTY(EditAnywhere, Category = "ArcGISMapsSDK|MyCppOAuth")
        FString RedirectURI;
    
    UPROPERTY(EditAnywhere, Category = "ArcGISMapsSDK|MyCppOAuth")
        FString ServiceURL;
    
  7. Create the method that will execute your code. In our example, we named it CreateArcGISMap() and set it to private.

    Use dark colors for code blocksCopy
     
    1
    void CreateArcGISMap();
  8. Remove your_project_file_API from your class declaration.

This is the complete source code for our header file:

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
#pragma once

#include "CoreMinimal.h"
#include "ArcGISMapsSDK/Actors/ArcGISActor.h"
#include "CppOAuth.generated.h"

UCLASS()
class ACppOAuth : public AArcGISActor
{
    GENERATED_BODY()

public:
    // Sets default values for this actor's properties
    ACppOAuth();

    // UObject
#if WITH_EDITOR
    void PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) override;
#endif

    // IArcGISMapsSDKSubsystemListener
       void OnArcGISMapViewChanged(AArcGISMapView* InArcGISMapView) override;

protected:
    UPROPERTY(EditAnywhere, Category = "ArcGISMapsSDK|MyCppOAuth")
        TEnumAsByte<EArcGISMapType::Type> MapType;

    UPROPERTY(EditAnywhere, Category = "ArcGISMapsSDK|MyCppOAuth")
        FString ClientID;

    UPROPERTY(EditAnywhere, Category = "ArcGISMapsSDK|MyCppOAuth")
        FString RedirectURI;

    UPROPERTY(EditAnywhere, Category = "ArcGISMapsSDK|MyCppOAuth")
        FString ServiceURL;

private:
void CreateArcGISMap();
};

Include headers and create Renderer Component

  1. First, include all necessary headers.

    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
    #include "CppOAuth.h"
    
    #include "Engine/World.h"
    
    // ArcGISMapsSDK
    
    #include "ArcGISMapsSDK/API/GameEngine/Layers/ArcGISImageLayer.h"
    #include "ArcGISMapsSDK/API/GameEngine/Security/ArcGISAuthenticationManager.h"
    #include "ArcGISMapsSDK/API/GameEngine/Security/ArcGISOAuthAuthenticationConfiguration.h"
    #include "ArcGISMapsSDK/BlueprintNodes/GameEngine/Elevation/ArcGISImageElevationSource.h"
    #include "ArcGISMapsSDK/BlueprintNodes/GameEngine/Layers/Base/ArcGISLayerCollection.h"
    #include "ArcGISMapsSDK/BlueprintNodes/GameEngine/Layers/ArcGISImageLayer.h"
    #include "ArcGISMapsSDK/BlueprintNodes/GameEngine/Map/ArcGISMap.h"
    #include "ArcGISMapsSDK/BlueprintNodes/GameEngine/Map/ArcGISMapType.h"
    #include "ArcGISMapsSDK/BlueprintNodes/GameEngine/Map/ArcGISBasemap.h"
    #include "ArcGISMapsSDK/BlueprintNodes/GameEngine/Map/ArcGISMapElevation.h"
    #include "ArcGISMapsSDK/Components/ArcGISRendererComponent.h"
    #include "ArcGISMapsSDK/Subsystem/ArcGISMapsSDKSubsystem.h"
    
    // ArcGISSamples
    
    #include "ArcGISSamples/Private/Security/SampleOAuthAuthenticationChallengeHandler.h"
  2. In the constructor, create a new Renderer Component and attach it to your main Actor with the following code.

    Use dark colors for code blocksCopy
             
    1
    2
    3
    4
    5
    6
    7
    8
    9
    ACppOAuth::ACppOAuth()
    {
        PrimaryActorTick.bCanEverTick = false;
    
        auto ArcGISRendererComponent = CreateDefaultSubobject<UArcGISRendererComponent>(TEXT("ArcGISRendererComponent"));
    
        AddOwnedComponent(ArcGISRendererComponent);
        SetRootComponent(ArcGISRendererComponent);
    }
    
  3. Call the method CreateArcGISMap() for the ArcGIS Subsystem Listener.

    Use dark colors for code blocksCopy
             
    1
    2
    3
    4
    5
    6
    7
    8
    9
    void ACppOAuth::OnArcGISMapViewChanged(AArcGISMapView* InArcGISMapView)
    {
        AArcGISActor::OnArcGISMapViewChanged(InArcGISMapView);
    
       if (ArcGISMapView)
       {
           CreateArcGISMap();
       }
    }
    
  4. To trigger the OAuth challenge handler during the editor mode when you introduce values in the Details panel, add a function to update the Viewport for the change events.

    Use dark colors for code blocksCopy
                  
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    #if WITH_EDITOR
    void ACppOAuth::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent)
    {
        Super::PostEditChangeProperty(PropertyChangedEvent);
    
        if (PropertyChangedEvent.MemberProperty->GetFName() == GET_MEMBER_NAME_CHECKED(ACppOAuth, MapType) ||
            PropertyChangedEvent.MemberProperty->GetFName() == GET_MEMBER_NAME_CHECKED(ACppOAuth, ClientID) ||
            PropertyChangedEvent.MemberProperty->GetFName() == GET_MEMBER_NAME_CHECKED(ACppOAuth, RedirectURI) ||
            PropertyChangedEvent.MemberProperty->GetFName() == GET_MEMBER_NAME_CHECKED(ACppOAuth, ServiceURL))
        {
            CreateArcGISMap();
        }
    }
    #endif

Create ArcGIS map

  1. Create your main function:

    Use dark colors for code blocksCopy
        
    1
    2
    3
    4
    void ACppOAuth::CreateArcGISMap()
    {
    
    }
    
  2. In the main function, trim the strings if there is any extra space.

    Use dark colors for code blocksCopy
       
    1
    2
    3
    auto trimmedClientID = ClientID.TrimStartAndEnd();
    auto trimmedRedirectURI = RedirectURI.TrimStartAndEnd();
    auto trimmedServiceURL = ServiceURL.TrimStartAndEnd();
  3. Add a method to check if the input string is empty or not.

    Use dark colors for code blocksCopy
        
    1
    2
    3
    4
    if (trimmedClientID.IsEmpty() || trimmedRedirectURI.IsEmpty() || trimmedServiceURL.IsEmpty())
    {
        return;
    }
    
  4. Add a method to use the SampleOAuthAuthenticationChallengeHandler while the editor mode is enabled.

    Use dark colors for code blocksCopy
                
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    if (UWorld* OwningWorld = GetWorld(); OwningWorld && OwningWorld->WorldType != EWorldType::Inactive)
    {
        if (auto arcGISMapsSDKSubsystem = OwningWorld->GetSubsystem<UArcGISMapsSDKSubsystem>())
        {
            if (!arcGISMapsSDKSubsystem->HasAuthenticationChallengeHandler())
            {
                auto arcGISOAuthAuthenticationChallengeHandler = NewObject<USampleOAuthAuthenticationChallengeHandler>();
    
                arcGISMapsSDKSubsystem->SetAuthenticationChallengeHandler(arcGISOAuthAuthenticationChallengeHandler);
            }
        }
    }
    
  5. Before using the authentication configuration from the Details panel, clean the global AuthenticationConfigurations.

    Use dark colors for code blocksCopy
     
    1
    Esri::GameEngine::Security::ArcGISAuthenticationManager::GetAuthenticationConfigurations().RemoveAll();
  6. Set authenticationConfiguration variable for the ArcGISOAuthAuthenticationConfiguration class.

    Use dark colors for code blocksCopy
     
    1
    Esri::GameEngine::Security::ArcGISOAuthAuthenticationConfiguration authenticationConfiguration;
  7. Configure the authenticationConfiguration variable to use the ArcGIS Identity.

    Use dark colors for code blocksCopy
      
    1
    2
    authenticationConfiguration =
        Esri::GameEngine::Security::ArcGISOAuthAuthenticationConfiguration(TCHAR_TO_ANSI(*trimmedClientID), "", TCHAR_TO_ANSI(*trimmedRedirectURI));
  8. Insert your private service URL and the proper authentication configuration into the global AuthenticationConfigurations.

    Use dark colors for code blocksCopy
      
    1
    2
    Esri::GameEngine::Security::ArcGISAuthenticationManager::GetAuthenticationConfigurations().Insert(TCHAR_TO_ANSI(*ServiceURL),
        authenticationConfiguration);
    
  9. Create the map document and use the MapType that is set in the Details panel. See the Global scene and the Local scene to know more about MapType.

    Use dark colors for code blocksCopy
     
    1
    auto arcGISMap = UArcGISMap::CreateArcGISMapWithMapType(MapType);
  10. Set a basemap layer with a basemap URL and add an elevation layer as the elevation source. For more information about adding a basemap and an elevation, see Display the globe (C++ API) or Display a specific area (C++ API).

    Use dark colors for code blocksCopy
            
    1
    2
    3
    4
    5
    6
    7
    8
    auto arcGISBasemap = UArcGISBasemap::CreateArcGISBasemapWithBasemapSource(
        "https://www.arcgis.com/sharing/rest/content/items/716b600dbbac433faa4bec9220c76b3a/data", "");
    arcGISMap->SetBasemap(arcGISBasemap);
    
    auto elevationSource = UArcGISImageElevationSource::CreateArcGISImageElevationSourceWithName(
        "https://elevation3d.arcgis.com/arcgis/rest/services/WorldElevation3D/Terrain3D/ImageServer", "Elevation", "");
    auto mapElevation = UArcGISMapElevation::CreateArcGISMapElevationWithElevationSource(elevationSource);
    arcGISMap->SetElevation(mapElevation);
  11. Create a new layer from the private service URL with its name, opacity, and visibility, and add it to the map.

    Use dark colors for code blocksCopy
      
    1
    2
    auto imageLayer = UArcGISImageLayer::CreateArcGISImageLayerWithProperties(TCHAR_TO_ANSI(*trimmedServiceURL), "MyLayer_1", 1.0f, true, "");
    arcGISMap->GetLayers()->Add(imageLayer);
  12. Add this code to print the error when the authentication fails.

    Use dark colors for code blocksCopy
             
    1
    2
    3
    4
    5
    6
    7
    8
    9
    auto layerAPIObject = StaticCastSharedPtr<Esri::GameEngine::Layers::ArcGISImageLayer>(imageLayer->APIObject);
    layerAPIObject->SetLoadStatusChanged([layerAPIObject](Esri::ArcGISRuntime::LoadStatus loadStatus) {
        if (loadStatus == Esri::ArcGISRuntime::LoadStatus::FailedToLoad)
        {
            auto loadError = layerAPIObject->GetLoadError();
    
            UE_LOG(LogTemp, Error, TEXT("Failed to load the ArcGISImageLayer: %s"), ANSI_TO_TCHAR(loadError.what()));
        }
        });
    
  13. Set the value for the ArcGISRendererViewOptions. If it's set to true you can change the layer's visibilities during the runtime.

    Use dark colors for code blocksCopy
     
    1
    FArcGISRendererViewOptions rendererViewOptions{ true };
  14. ArcGIS Map View Actor communicates with the ArcGIS Renderer Component that has the ArcGISRendererView to take care care of your camera and your map document. Set the RendererViewOptions and arcGISMap to the ArcGISMapView.

    Use dark colors for code blocksCopy
      
    1
    2
    ArcGISMapView->SetViewOptions(rendererViewOptions);
    ArcGISMapView->SetMap(arcGISMap);

You have created the C++ source code for a Map to load a private raster tile layer. Compile the project and Unreal Engine will be automatically opened.

Set up ArcGIS Map View

**ArcGIS Map View** Actor will place your GIS content in Unreal Engine space, and you can enable/disable the editor mode and Mesh Colliders. In this tutorial, you will configure where your GIS content is to be placed at `0, 0, 0` of the game engine space.

You can find the ArcGIS Map View Actor here:

Plugins\ArcGIS Maps SDK for Unreal Engine C++ Classes\ArcGISMapsSDK\Public\ArcGISMapsSDK\Actors

  1. Drag the ArcGIS Map View Actor into the level.

    ArcGISMapView Actor

  2. Configure the Origin Position with a WKID for the values. In this tutorial, you are setting up the following Origin Position values for New York City.

    • Longitude: -74
    • Latitude: 40
    • Spatial Reference WKID: 4326
    • Altitude: 0

    This is the result of the ArcGIS Map View Actor.

    ArcGIS Map View Result

Add the OAuth Actor

  1. Locate the CppOAuth Actor in the Content Drawer. Drag and drop the Actor you created into the level.
  2. In the Details panel, open the ArcGIS Maps SDK > MyCppAuth category.
  3. Set the Map Type, Client ID, Redirect URI, and Service URL.

When the Viewport loads Service URL data to render, it will display a login window.

Log in

Set up a Sample Pawn

To configure the camera, add the ArcGIS Pawn into the level.

  1. Select ArcGIS Pawn Actor and drag it into the level from the Content Drawer.

    Pawn

  2. Click the Actor and select ArcGIS Location Component in the Details panel.

  3. In the ArcGIS Location Component, set the Position to:

    • Longitude: -74.054921
    • Latitude: 40.691242
    • Spatial Reference WKID: 4326
    • Altitude: 3000 Meters
  4. Set the Rotation to:

    • Heading: 55
    • Pitch: 58
    • Roll: 0

This is the result of the ArcGIS Pawn.

Pawn local Result

Set up the sky and the light

  1. From the quick add menu on the toolbar, select Lights > Directional Light and drag it into the level to create a Directional Light. For more information about Directional Lights, see Lights.

    Directional Light

  2. Select the Directional Light in the Outliner, and open the Transform section in the Details window.

  3. Reset the Location and Set the Rotation to:

    • X: 0
    • Y: -28
    • Z: -28
  4. Set the Mobility to Movable.

    Directional Light Transform

  5. In the Light section, change the Intensity Value to 3.1416.

  6. In the Cascaded Shadow Maps section, change the Dynamic Shadow Distance MovableLight from 20000 to 2000000.

  7. In the Atmosphere and Cloud section, enable Atmosphere Sun Light.

  8. In the Actor > Spawn Collision Handling Method section, select Always Spawn, Ignore Collisions.

    Directional Light Actor

  9. From the quick add menu on the toolbar, select Lights > Sky Light and drag it into the level to create a Sky Light. For more information about Sky Light, see Lights.

  10. In the Transform section, reset the Location and set the Mobility to Movable.

  11. In the Light section, enable Real Time Capture.

    SkyLight

  12. From the quick add menu on the toolbar, select Visual Effects > Sky Atmosphere and drag it into the level to create a Sky. For more information about Sky Atmosphere, see Fog Effects.

  13. In the Planet section, change the Ground Radius to 6378.137207.

Click on Play to run the app and see your map.

Use the WASD keys to move left, right, forward, and backward. Move the mouse to move the camera's perspective.

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