Skip to content

Commit

Permalink
Merge b01a820 into 30fadcb
Browse files Browse the repository at this point in the history
  • Loading branch information
jgravois committed Sep 20, 2018
2 parents 30fadcb + b01a820 commit 17a7270
Show file tree
Hide file tree
Showing 10 changed files with 257 additions and 16 deletions.
9 changes: 5 additions & 4 deletions demos/batch-geocoder-node/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@
:loudspeaker: Node.js 8.6 or higher is [required](http://node.green/), this demo uses a couple shiny new JS features like `{... }`

1. Make sure you run `npm run bootstrap` in the root folder to setup the dependencies
2. Replace values in [config-template.js](/demos/batch-geocoder/config-template.js) and rename to `config.js`
1. `"un"`: ArcGIS username
2. `"pw"`: ArcGIS password
2. Create and register a [new application](https://developers.arcgis.com/documentation/core-concepts/security-and-authentication/accessing-arcgis-online-services/).
3. Replace values in [config-template.js](/demos/batch-geocoder/config-template.js) and rename to `config.js`
1. `"clientId"`: ArcGIS ClientId
2. `"clientSecret"`: ArcGIS ClientSecret
3. `"csv"`: csv path
4. `"output"`: output csv path
5. `"fieldmap"`: `object` that maps CSV fields to [address fields](https://esri.github.io/arcgis-rest-js/api/geocoder/IAddressBulk/) __or__ `string` that points to a CSV field with single-line addresses
3. `npm start`
4. `npm start`

Sample Restaurant Inspections adapted from a DOHMH dataset available [online](https://data.cityofnewyork.us/Health/DOHMH-New-York-City-Restaurant-Inspection-Results/xx67-kt59/data)
12 changes: 6 additions & 6 deletions demos/batch-geocoder-node/batch-geocode.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ require('isomorphic-fetch');
require('isomorphic-form-data');
const fs = require('fs');
const Papa = require('papaparse');
const { UserSession } = require('@esri/arcgis-rest-auth');
const { ApplicationSession } = require('@esri/arcgis-rest-auth');
const { bulkGeocode } = require('@esri/arcgis-rest-geocoder');
const config = require('./config');

Expand Down Expand Up @@ -77,10 +77,10 @@ const mapResults = results =>

// IMPLEMENTATION!

// Instantiate a user session to run Geocoding service
const session = new UserSession({
username: config.un,
password: config.pw
// Instantiate an ApplicationSession to run Geocoding service
const session = new ApplicationSession({
clientId: config.clientId,
clientSecret: config.clientSecret
});

// Parse and geocode
Expand All @@ -91,7 +91,7 @@ parseCsv(config.csv)
const chunks = chunkGeocode(addrs, 1000);

// Geocode
const promises = chunks.map(chunk =>
const promises = chunks.map(chunk =>
bulkGeocode({
addresses: chunk,
authentication: session //,
Expand Down
4 changes: 2 additions & 2 deletions demos/batch-geocoder-node/config-template.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module.exports = {
"un": "<USERNAME>",
"pw": "<PASSWORD>",
"clientId": "[public]",
"clientSecret": "[secret]",
"csv": "NYC_Restaurant_Inspection_Results.csv",
"output": "NYC_Restaurant_Inspection_Results_Geocoded.csv",
"fieldmap": {
Expand Down
25 changes: 25 additions & 0 deletions demos/oauth2-browser-retry/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# ArcGIS Rest JS / Vanilla JS Demo

This demo shows how to trigger OAuth 2.0 using `@esri/arcgis-rest-js` _after_ an anonymous request and a `403/499` is encountered using [`ArcGISAuthError.retry()`](https://esri.github.io/arcgis-rest-js/api/request/ArcGISAuthError/#retry-summary).

```js
request(url)
.catch(err => {
if (err.name === "ArcGISAuthError") {
// make the same request again with a UserSession
err.retry(appendSession)
.then(response => console.log(response))
}
})

appendSession = () => {
return UserSession.beginOAuth2({
clientId,
redirectUri: 'https://yourapp.com/authenticate.html'
});
}
```
Demo - [OAuth 2.0 Browser -retry](https://github.com/Esri/arcgis-rest-js/tree/master/demos/oauth2-browser-retry)

## Running this demo
1. open `index.html` in a web browser
21 changes: 21 additions & 0 deletions demos/oauth2-browser-retry/authenticate.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>ArcGIS Rest JS Vanilla JS - redirect</title>
</head>
<body>
<script src="https://unpkg.com/@esri/arcgis-rest-auth"></script>
<script>
// arcgis-rest-js ensures the clientId is associated with the state parameter by default.
const match = window.location.href.match(
/&state=(.+)/
);
const clientId = match[1];

arcgisRest.UserSession.completeOAuth2({
clientId: clientId,
});
</script>
</body>
</html>
116 changes: 116 additions & 0 deletions demos/oauth2-browser-retry/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>ArcGIS REST JS Browser OAuth2 - retry</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<script src="https://cdn.polyfill.io/v2/polyfill.js?features=es5,Promise,fetch"></script>
</head>
<body>
<div id="app-wrapper">
<div class="jumbotron">
<div class="container">
<div id="page-header" class="row">
<div id="logo-container" class="col-sm-3">
<img id="logo" src="./logo.svg">
</div>
<div class="col-sm-9">
<h2>
ArcGIS REST JS Browser OAuth 2.0
</h2>
<p>
An application demonstrating how to retry a request that requires authentication.
</p>
</div>
</div>
</div>
</div>
<div class="container">
<div class="row">
<div class="col-xs-12">
<div id="clientIdGroup" class="form-group">
<label class="control-label">ClientID</label>
<!-- This is input required for the app. -->
<input
id="clientId"
type="text"
class="form-control"
value="QVQNb3XfDzoboWS0"
>
</div>
<p class="help-block">
You can generate your own clientid by creating an application on the
<a target='_blank' href='https://developers.arcgis.com/documentation/core-concepts/security-and-authentication/browser-based-user-logins/'>
ArcGIS for Developers
</a>
website and adding
<code id="redirect_uri">
<!-- Redirect URI will be injected here. -->
</code>
as a redirect uri.
</p>
</div>
</div>
<div class="row">
<div class="col-xs-6">
<!-- Event listeners will be added to these buttons. -->
<button class="btn btn-primary btn-block" id='try'>Make an anonymous request that requires authentication</button>
</div>
</div>

<div class="row">
<div class="col-xs-12 text-center">
<p id="sessionInfo" class="info-panel">
<!-- Information will be injected here. -->
</p>
</div>
</div>
</div>
</div>

<script src="https://unpkg.com/@esri/arcgis-rest-request"></script>
<script src="https://unpkg.com/@esri/arcgis-rest-auth"></script>
<script>

// Define the variable used for the redirect uri.
const redirect_uri = window.location.origin + window.location.pathname;

// Inject that value into the page text.
document.getElementById('redirect_uri').innerHTML = redirect_uri;
const sessionInfo = document.getElementById('sessionInfo');

// Attach a listener to the sign in buttons.
document.getElementById('try').addEventListener('click', function (event) {
event.preventDefault();

// url that is NOT accessible to anonymous users
const url = `https://route.arcgis.com/arcgis/rest/services/World/Route/NAServer/Route_World`

arcgisRest.request(url)
.catch(err => {
if (err.name === "ArcGISAuthError") {
sessionInfo.classList.add('bg-info');
sessionInfo.innerHTML = 'error: ' + err.message;

// make the same request again with a UserSession
err.retry(appendSession)
.then(response => {
sessionInfo.classList.remove('bg-info');
sessionInfo.classList.add('bg-success');
sessionInfo.innerHTML = 'current version of private server: ' + response.currentVersion;
})
}
})
});

function appendSession () {
// Begin an OAuth2 login using a popup.
return arcgisRest.UserSession.beginOAuth2({
clientId: clientId.defaultValue,
redirectUri: redirect_uri + 'authenticate.html',
popup: true
});
}
</script>
</body>
</html>
4 changes: 4 additions & 0 deletions demos/oauth2-browser-retry/logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
22 changes: 22 additions & 0 deletions docs/src/guides/browser-authentication.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,25 @@ group: 2-authentication
---

# Authentication in Browser-based Apps

In the [Node.js](../node/) guide we explained how to instantiate an [`ApplicationSession`](/arcgis-rest-js/api/auth/ApplicationSession/) with hardcoded credentials. In the browser, you need to use [OAuth 2.0](https://developers.arcgis.com/documentation/core-concepts/security-and-authentication/signing-in-arcgis-online-users/) and have users can sign directly into [ArcGIS Online](https://www.arcgis.com) or ArcGIS Enterprise.

![browser based login](https://developers.arcgis.com/documentation/core-concepts/security-and-authentication/images/authorization-screen.png)

```js
// register your own app to create a unique clientId
const clientId = "abc123"

UserSession.beginOAuth2({
clientId,
redirectUri: 'https://yourapp.com/authenticate.html'
})
.then(session)
```

After they've signed in the `session` will keep track of individual `trustedServers` that are known to be federated and pass tokens through automatically.

### Demos

* [OAuth 2.0 Browser](https://github.com/Esri/arcgis-rest-js/tree/master/demos/oauth2-browser)
* [Retrying Requests](https://github.com/Esri/arcgis-rest-js/tree/master/demos/oauth2-browser-retry)
48 changes: 44 additions & 4 deletions docs/src/guides/node.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,49 @@ require("isomorphic-form-data");

const { request } = require("@esri/arcgis-rest-request");

request("https://www.arcgis.com/sharing/rest/info").then(response => {
console.log(response);
});
request("https://www.arcgis.com/sharing/rest/info")
.then(response);
```
Demo - [Express Application](https://github.com/Esri/arcgis-rest-js/tree/master/demos/express)

## Authentication

To access premium content and services without asking for user credentials, using a [Proxy Service](https://developers.arcgis.com/documentation/core-concepts/security-and-authentication/working-with-proxies/) or [App Login](https://developers.arcgis.com/documentation/core-concepts/security-and-authentication/accessing-arcgis-online-services/) is typically the best approach.

Proxy Service
```js
// no auth required
request(`https://utility.arcgis.com/usrsvcs/appservices/{unique}/rest/services/World/Route/NAServer/Route_World/solve`)
```
App Login
```js
const authentication = new ApplicationSession({
clientId: "public",
clientSecret: "secret"
})

// url not accessible to anonymous users
const url = `https://route.arcgis.com/arcgis/rest/services/World/Route/NAServer/Route_World`

// token will be appended by rest-js
request(url, {
authentication
})
```

Demo - [batch geocoding](https://github.com/Esri/arcgis-rest-js/tree/master/demos/batch-geocoder-node)

Applications cannot [create, update, share, modify of delete items](https://developers.arcgis.com/documentation/core-concepts/security-and-authentication/limitations-of-application-authentication/) in ArcGIS Online or ArcGIS Enterprise. For this, a [`UserSession`](/arcgis-rest-js/api/auth/UserSession/) is more appropriate.

```js
// hardcoded username / password
const authentication = new UserSession({
username: "jsmith",
password: "123456"
})
```
See the [Browser Authenication](../browser-authentication/) for more information about implementing OAuth 2.0.




[Demo express application](https://github.com/Esri/arcgis-rest-js/tree/master/demos/express)
12 changes: 12 additions & 0 deletions packages/arcgis-rest-auth/src/ApplicationSession.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,18 @@ export interface IApplicationSessionOptions {
expires?: Date;
}

/**
* ```js
* // visit https://developers.arcgis.com to generate your own clientid and secret
* const session = new ApplicationSession({
* clientId,
* clientSecret
* })
* ```
* You can use [App Login](https://developers.arcgis.com/documentation/core-concepts/security-and-authentication/accessing-arcgis-online-services/) to access premium content and services in ArcGIS Online.
* in `request`.
*
*/
export class ApplicationSession implements IAuthenticationManager {
public portal: string;
private clientId: string;
Expand Down

0 comments on commit 17a7270

Please sign in to comment.