Many premium ArcGIS Online services such as routing and GeoEnrichment (see available services below) require access tokens. Client secrets should never be exposed in any client-side application, whether your app is browser-based, a native app, or a hybrid. In order to implement a secure app you do not want to expose the token in a client-side app where it could be hijacked and used without your knowledge.
One method to mitigate this security risk is to use a proxy service that will store and manage your credentials and provide authentication. Your client-side app sends security sensitive requests to a proxy service, the proxy adds the necessary secrets, and then forwards the request to the service. The service sends the reply back to your proxy and your proxy forwards the reply back to your app. Other benefits are controls over rate limits and allowed referrers to prevent runaway usage but enable publicly accessible version of these premium services.
Esri provides two methods you can choose from to deploy a proxy service for your app:
- ArcGIS Online hosted proxy service configured on the ArcGIS for Developers website providing publically accessible endpoints for many premium services.
- A self-hosted resource proxy built in PHP, .NET, or Java that can proxy any ArcGIS service. Esri provides the source code on github.
ArcGIS Online hosted proxy
To use the proxy services hosted by Esri follow these steps:
-
Create a new application or go to an existing application on your application page.
-
If the app was not previously registered, select Register Application.
-
Click on the Services tab.
-
Select the service you wish to proxy and enter a rate limit for the number requests you want to allow over a given period.
-
You can also configure a list of allowed referrers that can access this proxy. We recommend configuring allowances for your application domains in development and production.
-
You can now use the new proxy URL that you are given to access the premium service you selected.
Available services
You can proxy the following services with this method:
Service | Proxy Value |
---|---|
Geocoding | geocode |
Geoenrichment | geoenrichment |
Routing | route |
Routing (Async) | asyncRoute |
Routing Utilities | routingUtilities |
Closest Facility | closestFacility |
Closest Facility (Async) | asyncClosestFacility |
Service Area | serviceArea |
Service Area (Async) | asyncServiceArea |
Location Allocation | asyncLocationAllocation |
Vehicle Routing Problem | syncVRP |
Vehicle Routing Problem (Async) | asyncVRP |
Origin Destination Cost Matrix Service | asyncODCostMatrix |
World Traffic | traffic |
Elevation | elevation |
Elevation | elevationSync |
Hydrology | hydrology |
Self-hosted proxy service
Esri maintains source code to implement a server-side proxy service with PHP, .NET, and Java. These proxy services can be configured with your Client ID and Client Secret and when used with either the ArcGIS Runtime SDKs, ArcGIS API for JavaScript or Esri Leaflet will allow you to consume premium services with the token exchange handled by the proxy. Each project includes installation instructions and information regarding system requirements. Follow these instructions to setup and configure the proxy service on your web server.
This proxy services allow you to use an ArcGIS Online service that requires a token for secure access without storing that token with the client app where it could potentially be compromised by a hacker. Non-secure services that do not require a token are also serviced by the proxy. The proxy service also supports an allowed list based on the HTTP Referer
header and service rate limiting.
Proxy service configuration
Below is a sample proxy configuration (proxy.config
) that allows access to both the routing and GeoEnrichment services. There are several mechanisms available for restricting access to these resources:
- Set which HTTP Referrers should be allowed to access these resources with the
allowedReferers
attribute. - On a service by service basis, configure a
rateLimit
andrateLimitPeriod
(in minutes) to limit request frequency during the rate limit period.
<ProxyConfig
mustMatch="true"
logFile="proxy_log_xml.log"
allowedReferers="example.com">
<serverUrls>
<serverUrl
url="geoenrich.arcgis.com"
oauth2Endpoint="https://www.arcgis.com/sharing/oauth2"
clientId="6Xo1d-example-9Kn2"
clientSecret="5a5d50-example-c867b6efcf969bdcc6a2"
rateLimit="120"
rateLimitPeriod="60"
matchAll="true"/>
<serverUrl
url="route.arcgis.com"
matchAll="true"
oauth2Endpoint="https://www.arcgis.com/sharing/oauth2"
clientId="6Xo1d-example-9Kn2"
clientSecret="5a5d50-example-c867b6efcf969bdcc6a2"
rateLimit="120"
rateLimitPeriod="60"/>
</serverUrls>
</ProxyConfig>
See Proxy Configuration Settings on Github for a full list of XML configuration properties.
Assuming the proxy is hosted at URL /proxy.php
you can send it the following request:
/proxy.php?http://geoenrich.arcgis.com/arcgis/rest/services/World/GeoenrichmentServer/Geoenrichment/enrich?studyAreas=[{"geometry":{"x":-117.1956,"y":34.0572}}]
Assuming the request came from one of your allowedReferers
and the geoenrich.arcgis.com
resource was under its rate limit, your request would succeed without requiring a token (because the token was supplied by the proxy service.)
Using proxies
Support for proxy services is provided with ArcGIS API for JavaScript and Esri Leaflet.
ArcGIS API for JavaScript
The ArcGIS API for JavaScript can be configured to automatically route all requests through a proxy when the request matches a given URL pattern. The following code would route all requests matching geoenrich.arcgis.com
through the proxy at /proxy.php
.
urlUtils.addProxyRule({
urlPrefix: "geoenrich.arcgis.com",
proxyUrl: "/proxy.php"
});
Learn more about configuring proxies in the ArcGIS API for JavaScript.
Esri Leaflet
Esri Leaflet also supports using proxies with L.esri.Services.Service
.
var geoenrichment = L.esri.Services.Service('https://geoenrich.arcgis.com/arcgis/rest/services/World/geoenrichmentserver/GeoEnrichment/', {
proxy: '/proxy.php'
});
// now all requests made using this service will be routed through the proxy.
geoenrichment.get('enrich', {
studyAreas: [{
"geometry":{
"x":-117.1956,
"y":34.0572
}
}
]
}, callback);