Token update using removeLayer, addLayer. Is there a better way?

4404
10
Jump to solution
02-11-2015 08:50 PM
BlairJones
New Contributor III

I have reviewed many discussions on this forum where a desire is expressed to refresh access tokens using JavaScript. I have not found an elegant solution.

Is there a better way?  Just updating the .url property of a layer with a fresh token does not work.  A not very elegant way to change a token is to use method removeLayer followed by method addLayer with a url string that includes a fresh token ( many undesirable side effects ).

I want to manage access based on credentials entered on my login page.  On Windows platform running IIS, It is easy to get a fresh token string from a process running in the same IIS Session used by login page with all sensitive credentials safe as Session variables.  A fresh token string can easily be obtained by JavaScript in a subsequent map web page run in the same session with a new layer added using this token part of the url parameter.  What is surprisingly not easy is to update an existing map layer's access token.  I do not understand how to best do this using esri.map JavaScript API documentation.

0 Kudos
1 Solution

Accepted Solutions
JoelBennett
MVP Regular Contributor

I had to look into this further because it also wasn't working properly with my own FeatureLayers.  I've found that FeatureLayers have a _task property which is an instance of QueryTask.  This _task property is created when the FeatureLayer is initialized, and its URL never appears to get updated after that (as far as I can tell).

Anyhow, I've revised the function to below (and it appears to be working properly).  Nothing like building an airplane while you're flying it...

function setLayerTokenProperties(layer, token, expires) {
 if ((layer) && (token)) {
  layer.url = addTokenToURL(token, layer.url);
  layer._url = urlUtils.urlToObject(layer.url);
  layer._params.token = token;
  if (layer.credential) {
   layer.credential.token = token;
   layer.credential.expires = expires;
  }
  if ((layer.declaredClass == "esri.layers.FeatureLayer") && (layer._task)) {
   layer._task.url = layer.url;
   layer._task._url = urlUtils.urlToObject(layer.url);
  }
 }
} 

View solution in original post

0 Kudos
10 Replies
JoelBennett
MVP Regular Contributor

Interesting you should ask since I was working on this yesterday.  Below you will find the essentials of my solution, and it appears to be working well with 3.12, although its elegance is debatable.  Note that "urlUtils" is esri/urlUtils - you'll have to figure out how best to work that module into your solution.

  function setLayerTokenProperties(layer, token) {
   if ((layer) && (token)) {
    layer.url = addTokenToURL(token, layer.url);
    layer._url = urlUtils.urlToObject(layer.url);
    layer._params.token = token;
   }
  }
  function addTokenToURL(token, url) {
   if ((url) && (token)) {
    var sIndex = url.indexOf("token=");
    if (sIndex > 0) {
     var eIndex = url.indexOf("&", sIndex + 1);
     if (eIndex > sIndex)
      return url.substring(0, sIndex) + "token=" + token + url.substr(eIndex);
     else
      return url.substring(0, sIndex) + "token=" + token;
    } else if (url.indexOf("?") > 0)
     return url + "&token=" + token;
    else
     return url + "?token=" + token;
   } else
    return url;
  }
0 Kudos
BlairJones
New Contributor III

Thanks for the reply. urlUtils.urlToObject seems defined well enough in the API documentation.

I have not seen these properties described anywhere; where do you find documentation?

  1.     layer._url
  2.     layer._params

I can't find any reference using web search.  Are these "special knowledge" things?  When one updates layer.url are these supposed to be updated automatically but are not being updated because of a bug? or are they updated in layer when method addLayer  is used?

I'll spend a few hours testing these and then I'll report back.

0 Kudos
BlairJones
New Contributor III

OK, reporting back...  setting those properties does not work for me.  Using Firefox browser.  I report the new token on my test page and assign those properties; but when I pan the map, the browser console shows new net references using the original token.  When I use removeLayer - AddLayer then the new net references show the new token.

0 Kudos
JoelBennett
MVP Regular Contributor

Unfortunately I cannot explain why it works for me and not you - my map wouldn't even load if it didn't.  I'm using IE 11, but don't think that's the culprit.

The _url and _params properties are not documented.  I found them by going into the source code for the layer classes (Layer, DynamicMapServiceLayer, ArcGISDynamicMapServiceLayer, etc).  It's unorthodox, but I have to thoroughly test between each new version of the API anyways...

0 Kudos
JoelBennett
MVP Regular Contributor

Once such possibility that might be causing this not to work for you is if your layers use the credential property (which mine do not).  If so, updating the setTokenLayerProperties method like below may make the difference (although I haven't tested this):

function setLayerTokenProperties(layer, token, expires) {
 if ((layer) && (token)) {
  layer.url = addTokenToURL(token, layer.url);
  layer._url = urlUtils.urlToObject(layer.url);
  layer._params.token = token;
  if (layer.credentials) {
   layer.credentials.token = token;
   layer.credentials.expires = expires;
  }
 }
}
0 Kudos
BlairJones
New Contributor III

Thanks for additional ideas, but my test if(layer.credentials) comes up false.

I did not mention I am working with  layer = new FeatureLayer( url, options );   Does your method work for you on layer constructed as FeatureLayer ?

0 Kudos
JoelBennett
MVP Regular Contributor

My code there was incorrect...it should be "layer.credential" (singular), not "layer.credentials" (plural).  That's what I get for posting untested code...

Yes, what I originally posted works with instances of ArcGISDynamicMapServiceLayer, ArcGISTiledMapServiceLayer, ArcGISImageServiceLayer, and FeatureLayer.

0 Kudos
BlairJones
New Contributor III

I am using initially

myLayer = new FeatureLayer(url+"?token="+initialToken,myOptions);

map.addLayer(myLayer);

I have tested for mayLayer.credential which comes up false.

and later associated with setTimeout

                        myLayer.url = url + "?token=" + newToken;

                        myLayer._url = urlUtils.urlToObject( myLayer.url );

                        myLayer._params.token = "" + newToken;

and then the browser console still shows net acgitvity to url using initialToken.  A new token is used only when I code

myLayer = new FeatureLayer(url+"?token="+newToken,myOptions);

0 Kudos
JoelBennett
MVP Regular Contributor

I had to look into this further because it also wasn't working properly with my own FeatureLayers.  I've found that FeatureLayers have a _task property which is an instance of QueryTask.  This _task property is created when the FeatureLayer is initialized, and its URL never appears to get updated after that (as far as I can tell).

Anyhow, I've revised the function to below (and it appears to be working properly).  Nothing like building an airplane while you're flying it...

function setLayerTokenProperties(layer, token, expires) {
 if ((layer) && (token)) {
  layer.url = addTokenToURL(token, layer.url);
  layer._url = urlUtils.urlToObject(layer.url);
  layer._params.token = token;
  if (layer.credential) {
   layer.credential.token = token;
   layer.credential.expires = expires;
  }
  if ((layer.declaredClass == "esri.layers.FeatureLayer") && (layer._task)) {
   layer._task.url = layer.url;
   layer._task._url = urlUtils.urlToObject(layer.url);
  }
 }
} 
0 Kudos