How to authenticated a portal item properly using AuthenticationManager

478
3
01-22-2024 11:47 AM
SeanS
by
New Contributor II

I am working on a .NET MAUI application that uses a secure webmap from Portal. I can authenticate the user successfully with the following code:

 

	CredentialRequestInfo credentialRequestInfo = new()
			{
				AuthenticationType = AuthenticationType.Token,
				ServiceUri = PortalURL,
				GenerateTokenOptions = new()
				{
					TokenAuthenticationType = TokenAuthenticationType.OAuthAuthorizationCode,
					TokenExpirationInterval = System.TimeSpan.MaxValue
				}
			};
			OAuthTokenCredential credentialRequestResponse = (await AuthenticationManager.Current.ChallengeHandler.CreateCredentialAsync(credentialRequestInfo)) as OAuthTokenCredential;
			AuthenticationManager.Current.AddCredential(credentialRequestResponse);

			var arcgisPortal = await ArcGISPortal.CreateAsync(PortalURL);

 

I am then creating a web map based on a specific arcgisPortal above using the following code

 

PortalItem _mapItem = await PortalItem.CreateAsync(arcgisPortal, portalItemId);

 

The problem I'm running into is that because some of the layers in the webmap have an Organization-level sharing set, it is prompting me to log in AGAIN to load the webmap, which has a less restrictive sharing set ("Public" for Enterprise users on the network) Is there a specific flow or way to utilize the credentials within the AuthenticationManager to get those items without prompting the user to log in again?


It also appears that there is a separate credential being added after logging into the Webmap page. I am doing this through the AuthenticationManager.Current.Credentials object. The first item is the Service URI of the first credential. The second item is the Service URI after logging in on the web map

 

https://portalname.com/arcgis/
https://portalname.com/gisserver/rest/services/folder/item/MapServer?f=json

 

 
Because both these items are located within the same portal, is there a way to utilize the first credential to get data from the second endpoint? I'm trying to prevent the user from having to log in multiple times.

3 Replies
dotMorten_esri
Esri Notable Contributor

Does your portal allow anonymous access? The authentication only triggers if sign in is required, otherwise it'll just sign you in anonymously. You can add a `true` parameter to portal creation to force creating a portal with an associated user:

 

var arcgisPortal = await ArcGISPortal.CreateAsync(PortalURL, true);

 

  Also try setting ServiceUri to just the domain of your server to scope it to all of it.

0 Kudos
SeanS
by
New Contributor II

Thank you for your reply @dotMorten_esri,
Our portal doesn't allow anonymous access, so adding that parameter didn't solve the problem. When I try setting the service URI to https://portalname.com/ rather than having https://portalname.com/arcgis/ (updating the ServerInfo that we registered as well) a 404 server error on the sign-in page.
I'm not sure the best way to use the Maps SDK to create a credential for https://portalname.com/...

0 Kudos
JoeHershman
MVP Regular Contributor

What I do as have a method to log onto the portal.  This cannot be done using the ChallangeHandler, you have to do yourself.  But this allows having a full portal login to the Portal itself, instead of specific resource

 

protected readonly string ServerUrl = "https://www.arcgis.com/sharing/rest";
//protected readonly string ServerUrl = "https://machine.domain.loc/portal/sharing/rest";


public async Task<ArcGISPortal> OpenPortalAsync(bool refresh = false)
{
	try
	{
		if ( _portal == null )
		{
			var credential = await AuthenticationManager.Current.GenerateCredentialAsync(new Uri(ServerUrl));
			RefreshToken(credential);

			AuthenticationManager.Current.AddCredential(credential);

			_portal = await ArcGISPortal.CreateAsync(new Uri(ServerUrl));
			PortalUser = _portal.User;
			ConnectionStatus = ConnectionStatus.Connected;
		}
		else
		{
			if ( !refresh ) return _portal;

			var token = (TokenCredential)await AuthenticationManager.Current.GetCredentialAsync(
				new CredentialRequestInfo { ServiceUri = new Uri(ServerUrl) }, false);

			if ( token != null ) await token.RefreshTokenAsync();
		}

		return _portal;
	}
	catch (Exception e)
	{
		_log.Debug(e.Message);
		ConnectionStatus = ConnectionStatus.NotConnected;
		return null;
	}
}

 

Thanks,
-Joe