Hi everyone,
I am trying to integrate the OAuth functionality in a simple app developed with the Web AppBuilder embedded with Portal and then deployed.
I have obtained the AppID and I have looked into the OAuth 2 basic sample, but I don't understand how to integrate it in my app.
I suppose that I have to modify the index.html, but I don't know how.
Can anyone point me in the right direction?
Thanks,
Marco
I have one example making app login with AGOL and this proxy-oauth. I just change the proxy.ashx and the Index.html for the application to request the TOKEn before load the application (inside the <script> tag for index.html).
Add the variables to web.config for the proxy configuration with username, password, clientid and clientsecret and make this changes like descrived:
<add key="user" value="loginname"/>
 <add key="pass" value="password"/>
 <add key="clientid" value="1111111111"/>
 <add key="clientsecret" value="2222222222222222222"/>
Change the function ProcessNormalRequest (inside proxy.ashx) to add one validation just like below (before make the URL request ~line 232):
if (uri.Contains("oauth2/token"))
 {
 // Get the AppSettings section.
 NameValueCollection appSettings = ConfigurationManager.AppSettings;
 string appSecret = "";
 string user = "";
 string pass = "";
 string clientid = "";
 string clientsecret = "";
 for (int i = 0; i < appSettings.Count; i++)
 {
 System.Diagnostics.Debug.WriteLine(appSettings.GetKey(i) + "," + appSettings);
 //if (appID == appSettings.GetKey(i))
 //{
 // appSecret = appSettings;
 //break;
 //}
 if ("user" == appSettings.GetKey(i))
 {
user = appSettings; 
 }
 if ("pass" == appSettings.GetKey(i))
 {
 pass = appSettings; 
 }
 if ("clientid" == appSettings.GetKey(i))
 {
 clientid = appSettings; 
 }
 if ("clientsecret" == appSettings.GetKey(i))
 {
 clientsecret = appSettings; 
 }
 }
 uri += "&username="+ user + "&password="+ pass + "&client_id=" + clientid + "&client_secret=" + clientsecret + "&grant_type=client_credentials";
 }
and in the index.html of the main application, insert one script just like below:
<script>
 /*******************************
 * This is the function you can modify to customize the loading page
 * This function will be invoked when one resource is loaded.
 ********************************/
 // var progress;
 // function loadingCallback(url, i, count) {
 // var loading = document.getElementById('main-loading-bar');
 // loading.setAttribute('title', url);
 // if(!progress){
 // progress = document.createElement('div');
 // progress.setAttribute('class', 'loading-progress');
 // loading.appendChild(progress);
 // }
 // progress.style.width = (((i - 1)/count) * 100) + '%';
 // }
 var xhr = new XMLHttpRequest();
xhr.open('POST', 'https://yourserver/proxyoauth/proxy.ashx?https://www.arcgis.com/sharing/rest/oauth2/token?expiration...', true);
 xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
 xhr.onreadystatechange = function () {
 // do something to response
 console.log(this.responseText);
 testeTopken = this.responseText;
 //expiraUTCformat = Date.now() + (testeTopken.substr(testeTopken.indexOf(',"expires_in":')+14, 5)*1000);
 expiraUTCformat = Date.now() + 86400000);
 testeEsriJSAPI1 = testeTopken.replace('{"access_token":','{"/":{"https://yourportalserver":{"expires":'+expiraUTCformat+',"ssl":true,"token":');
 testeEsriJSAPI1 = testeEsriJSAPI1.substr(0, testeEsriJSAPI1.indexOf(',"expires_in":'));
 testeEsriJSAPI1 = testeEsriJSAPI1 + ',"userId":"username"}}}';
 localStorage.setItem('esriJSAPIOAuth', testeEsriJSAPI1);
 };
 xhr.send(); 
 </script>
Hope this help you. 
Nothing to do: it keeps redirecting me to the same page. Probably I am missing something somewhere...
But thank you anyway, Rafael: you have been really kind!
I have a widget using OAuth2 functionality. In the widget's postcreate function, I call this function
  _logon() {
    var theAppId, thePopupCallbackUrl;
    var location = this._appInfo.find(x => x.location === window.location.hostname);
    if (location !== undefined) {
      theAppId = location.appID;
      thePopupCallbackUrl = location.popupCallbackUrl;
    } else {
      new Message({
        titleLabel: 'Error',
        message: 'This site will not allow ArcGIS.com login'
      });
      this._logoff();
      return;
    }
    var info = new ArcGISOAuthInfo({
      appId: theAppId,
      popupCallbackUrl: thePopupCallbackUrl,
      popup: true,
      portalUrl: this.config.agol.portalUrl
    });
    esriId.registerOAuthInfos([info]);
    esriId.getCredential(info.portalUrl, {
      oAuthPopupConfirmation: true
    }).then(lang.hitch(this, function () {
      new arcgisPortal.Portal(this.config.agol.portalUrl).signIn().then(lang.hitch(this, function (portalUser) {
        var portal = portalUser.portal;
        var queryParams = {
          num: 100,
          q: 'owner: ' + this._ownerName + ' AND type: Feature Service'
        };
        portal.queryItems(queryParams).then(lang.hitch(this, function (result) {
          if (result.total > 0) {
            if (array.some(result.results, lang.hitch(this, function (item) {
              this._SPGridUrl = item.url;
              return this._SPGridUrl.indexOf(this._baseGridLayerName) > -1;  //
            }))) {
              this._prepareEditor();
            } else {
              this._SPGridUrl = null;
              new Message({
                titleLabel: 'Logging out',
                message: 'The grid was not found in your account!'
              });
            }
          } else {
            this._SPGridUrl = null;
            new Message({
              titleLabel: 'Logging out',
              message: 'The grid is not available to edit!'
            });
          }
        }));
      }
      )).otherwise(
        function (error) {
          new Message({
            titleLabel: 'Error occurred while signing in',
            message: error
          });
        }
        );
    }))
      .otherwise(lang.hitch(this, this._promiseRejected));
  },When the user starts the widget, after they successfully log in, the code searches for a feature layer (which begins with the string indicated in the variable this._baseGridLayerName) in their AGOL contents and added to their map (in the _prepareEditor function). The variable this._appInfo contains the AppID and the popup callback URL. In my case, I have several of these defined, since I have versions running on my laptop, a development server, and the production server.
    this._appInfo = [
      {
        "location": "productionURL",
        "appID": "xxxxxxxxxxxxxxxxx",
        "popupCallbackUrl": "productionURL/oauth-callback.html"
      },
      {
        "location": "developmentURL",
        "appID": "xxxxxxxxxxxxxxxxx",
        "popupCallbackUrl": "developmentURL/oauth-callback.html"
      },
      {
        "location": "laptopURL",
        "appID": "xxxxxxxxxxxxxxxxx",
        "popupCallbackUrl": "./oauth-callback.html"
      }
    ]
					
				
			
			
				
			
			
				
			
			
			
			
			
			
		Thank you very much, Ken. I will look into your code and let you know if I can manage to replicate it.
I would have preferred a solution without the use of a widget, but I suppose that it will work just fine.
Sit Sit,
Please let me know if you were able to figure this out. I also have a WAB App that accesses secure services and I would like to use the OAuth Named User Login Popup instead of the AGOL Username and Password.
Thanks,
Scott