AppStudio : iOS session doesn't persiste

615
4
Jump to solution
05-22-2023 01:34 AM
GISiste
Occasional Contributor

Hello @ALL

I already posted this question on Qt Maps SDK Questions community and get redirected to AppStudio Community

My mobile app session under IOS doesn't persist after closing : the user needs to login every time to use the application

For my Android version, the user needs to login the first time only, then the session still available for the next times

Technique environment :

AppStudio : 5.1.80

QT : 5.15.2

ArcGIS Runtime SDK for QT : 100.11.2.3121

Does anyone have an idea about this issue

Tags (2)
1 Solution

Accepted Solutions
DavidPuckett
Occasional Contributor

Here's the core of the code I'm using. Assuming you have all the properties defined etc. You'll also need an AuthenticationView defined in scope somewhere too.

// assuming you have a AuthenticationView defined
// for signing into a portal instance
AuthenticationView {
	id: authView
	anchors.fill: parent
}
// this goes in your main app component
Component.onCompleted: {
	// we are using secure storage to store a refresh token that is attempted to be retrieved
	// if the secureStorage.getContent("appRefreshToken") returns an empty string
	// i.e. the refresh token has never been stored
	// then don't pass it into the credential which will prompt for sign in (using the authView defined above)
	// if the refresh token is successfully retrieved from storage pass it into the credential which will use it to generate a fresh token

	// create oAuth info specifying that we are requiring a named user sign in and a clientid unique to this app
	let oAuthClientInfo = ArcGISRuntimeEnvironment.createObject("OAuthClientInfo", {
				oAuthMode: Enums.OAuthModeUser,
				clientId: app.clientId
	});

	let credential = ArcGISRuntimeEnvironment.createObject("Credential", { oAuthClientInfo: oAuthClientInfo });

	// attempt to get the refresh token from storage
	// so it can be used to generate an access token rather than forcing user to log in again
	const refreshToken = secureStorage.getContent("appRefreshToken");

	// if we got a refresh token apply it to the credential
	// if we did not get one, returns empty string if the key is not found in storage
	// don't set the credential refresh token which will prompt for sign in via AuthenticationView
	// when loading the portal
	if(refreshToken !== "") {
		credential.oAuthRefreshToken = refreshToken;
		credential.tokenServiceUrl = "%1/sharing/rest/oauth2/token".arg(app.portalUrl);
	}

	app.portal = ArcGISRuntimeEnvironment.createObject("Portal", {url: app.portalUrl, credential: credential});
	app.portal.load();
	app.portal.onLoadStatusChanged.connect(()=>{
		if (app.portal.loadStatus === Enums.LoadStatusFailedToLoad) {
				console.log(app.portal.error.message);
				// assume our refresh token was invalidated so set to empty which prompts for log in
				app.portal.credential.oAuthRefreshToken = "";
				app.portal.retryLoad();
		}
		else if(app.portal.loadStatus === Enums.LoadStatusLoaded) {
				// store the refresh token and token service url for retrieval next time the app is started
				// so the user isn't prompted to log in again
				secureStorage.setContent("appRefreshToken", app.portal.credential.oAuthRefreshToken);
				secureStorage.setContent("tokenServiceUrl", app.portal.credential.tokenServiceUrl);
		}
	})
}

Good Luck! :collision:

View solution in original post

4 Replies
DavidPuckett
Occasional Contributor

You'll want to store the refresh token that you get back along with the access token when logging in initially. You can then retrieve that refresh token and use it to generate an access token each time the app is fired up. You'd only then be prompted for login when that refresh token expires. I think the default is 2 weeks (?). I pulled a solution together from a couple samples using SecureStorage. Sorry but I can't find the samples I used at the moment. I can drop a few lines of code here to help get you started if that would be helpful.

0 Kudos
GISiste
Occasional Contributor

Hello @DavidPuckett 

Thank you for your appreciated reply.

Yes please. I would like to see how you implemented this methode. 

Thanks again

Regards

0 Kudos
DavidPuckett
Occasional Contributor

Here's the core of the code I'm using. Assuming you have all the properties defined etc. You'll also need an AuthenticationView defined in scope somewhere too.

// assuming you have a AuthenticationView defined
// for signing into a portal instance
AuthenticationView {
	id: authView
	anchors.fill: parent
}
// this goes in your main app component
Component.onCompleted: {
	// we are using secure storage to store a refresh token that is attempted to be retrieved
	// if the secureStorage.getContent("appRefreshToken") returns an empty string
	// i.e. the refresh token has never been stored
	// then don't pass it into the credential which will prompt for sign in (using the authView defined above)
	// if the refresh token is successfully retrieved from storage pass it into the credential which will use it to generate a fresh token

	// create oAuth info specifying that we are requiring a named user sign in and a clientid unique to this app
	let oAuthClientInfo = ArcGISRuntimeEnvironment.createObject("OAuthClientInfo", {
				oAuthMode: Enums.OAuthModeUser,
				clientId: app.clientId
	});

	let credential = ArcGISRuntimeEnvironment.createObject("Credential", { oAuthClientInfo: oAuthClientInfo });

	// attempt to get the refresh token from storage
	// so it can be used to generate an access token rather than forcing user to log in again
	const refreshToken = secureStorage.getContent("appRefreshToken");

	// if we got a refresh token apply it to the credential
	// if we did not get one, returns empty string if the key is not found in storage
	// don't set the credential refresh token which will prompt for sign in via AuthenticationView
	// when loading the portal
	if(refreshToken !== "") {
		credential.oAuthRefreshToken = refreshToken;
		credential.tokenServiceUrl = "%1/sharing/rest/oauth2/token".arg(app.portalUrl);
	}

	app.portal = ArcGISRuntimeEnvironment.createObject("Portal", {url: app.portalUrl, credential: credential});
	app.portal.load();
	app.portal.onLoadStatusChanged.connect(()=>{
		if (app.portal.loadStatus === Enums.LoadStatusFailedToLoad) {
				console.log(app.portal.error.message);
				// assume our refresh token was invalidated so set to empty which prompts for log in
				app.portal.credential.oAuthRefreshToken = "";
				app.portal.retryLoad();
		}
		else if(app.portal.loadStatus === Enums.LoadStatusLoaded) {
				// store the refresh token and token service url for retrieval next time the app is started
				// so the user isn't prompted to log in again
				secureStorage.setContent("appRefreshToken", app.portal.credential.oAuthRefreshToken);
				secureStorage.setContent("tokenServiceUrl", app.portal.credential.tokenServiceUrl);
		}
	})
}

Good Luck! :collision:

GISiste
Occasional Contributor

Hello @DavidPuckett 

Thank your for your code. I appreciate !

I added this to my code and still testing. It sounds workign until now.

Regards

0 Kudos