4

I am building a web app in a low code platform (Mendix). I am connecting the web app with ArcGIS online resources via the ArcGIS JavaScript API v4.19, which all goes pretty smoothely.

The challenge arises when I want to load specific secured ArcGIS online content via the ArcGIS JavaScript API, specifically from some FeatureLayers which are secured. I looked into the documentation and it seems the best way forward would be a so-called 'application login'. For this I want to setup an OAuth application login based on CLient ID and Client Secret. With these two I can get a valid token via AOuth and use that token to access the content by feeding the token to the IdentityManager via the JavaScript API.

This is were it goes wrong currently, I can't seem to figure out where to make it explicit on the ArcGIS online side that this specific secured FeatureLayer can be accessed via this application login, hence currently I am getting errors that the valid token and app id don't have access to the resource, being the end-point of the secured FeatureLayer.

Does anybody know how to associate a secured FeatureLayer in ArcGIS online to a application login?

EDIT 10-6-2021: Added code sample

After succesfully retrieving a valid token on the server side based on client id and client secret I use the client ID (=AppID) and token in the ArcGIS JavaScript API like below:

const token = {
    server: "http://www.arcgis.com",
    userId: <AppID>,
    token:
        <valid token retrieved via OAuth generateToken request,
    ssl: true,
    expires: 7200
};
IdentityManager.registerToken(token);

Only implementing this gives me an error whilst trying to access the secured feature layer:

identity-manager:not-authorized. "You are currently signed in as: AppID. You do not have access to this resource: https://server/someid/arcgis/rest/services/somefeatureserver/FeatureServer/0

I also read that sometimes below could be needed so added as well:

const idString = JSON.stringify(IdentityManager.toJSON());
console.debug("idString: " + idString);
IdentityManager.initialize(idString);

This resolves the error but makes a login popup appear again.

The layer is afterwards declared like below:

const layer = new FeatureLayer({
    // URL to the service
    url: layerObj.layerURLStatic
    definitionExpression: queryDefinition,
    featureReduction: clusterConfig && { type: "cluster" },
    popupTemplate: {
        title: "{" + inAttributeTitle + "}",
        content: [
            {
                type: "fields", // FieldsContentElement
                fieldInfos
            }
        ],
        actions: [
            {
                title: props.intButtonLabel,
                id: btnId,
                className: props.intButtonClass + intButtonIconClass,
                type: "button"
            }
        ]
    },
    outFields: ["*"]
});

webMap.add(layer);
Ivo Sturm
  • 130
  • 7
  • Do you want your application user to provide client_id and client_secret, and then once they do, they layer will load? Or do you want to use your own, behind the scenes, and get the layer to load that way (meaning the layer just displays, no user login in the UI needed)? – Seth Lutske Jun 08 '21 at 14:22
  • Hi Seth, thanks for your comment! The application is already providing client_id + client_secret. Once the layer loads I get the error: identit-manager:not-authorized. I guess this is because the layer is accessible via this application type of login. Not sure where to set this on the ArcGIS Online side though, documentation from Esri is not the best on authentication.. – Ivo Sturm Jun 09 '21 at 07:07
  • 1
    Can you show some code as to how you are using your client_id and client_secret? And how you are declaring your layer? Obv don't show the secrets themselves, just the code with variable names. – Seth Lutske Jun 09 '21 at 14:21
  • Hi Seth, added some samples – Ivo Sturm Jun 10 '21 at 05:44
  • I have no experience with their OAuth protocols but if you do not find a solution - I just wanted to suggest- maybe add the token as a query parameter to the service URL, in some cases, it works. – Shaked Jun 13 '21 at 09:00
  • Tried that and didn't work.. – Ivo Sturm Jun 14 '21 at 10:03
  • Did you ever find a solution @Ivo ? – Joshua Abbott Apr 13 '22 at 22:19
  • Yes I did. I changed the way the token is retrieved, needed to change some header details. – Ivo Sturm Aug 11 '22 at 06:41

1 Answers1

1

Here is a snippet to generate the token and then register it with IdentityManager:

IdentityManager = require('esri/identity/IdentityManager')
function login(user, password){
  var serverInfo = {
    "server": "https://www.arcgis.com",
    "tokenServiceUrl" : "https://www.arcgis.com/sharing/generateToken"
  };
  var userInfo = {
    username : user,
    password : password
  }
  IdentityManager.generateToken(serverInfo, userInfo).then(function (response){
      response.server = serverInfo.server;
      response.userId = user;
      IdentityManager.registerToken(response);
  });
}

I'm not sure how you are going to fit this in you app, but the sample should work if you paste it in your developer tools console when the app is running.

Also, it seems to me that userId property is for arcgis online username, not for appId.

As pointed out by Shaked, if you append '?token=[token_value]' int the layer URL you probably don't even need to register the token to query the layer.

Carlos Nantes
  • 1,197
  • 1
  • 12
  • 23