<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:taxo="http://purl.org/rss/1.0/modules/taxonomy/" version="2.0">
  <channel>
    <title>topic Re: Credentials persistence on iOS: 'Invalid token.' error in particular case in Flutter Maps SDK Questions</title>
    <link>https://community.esri.com/t5/flutter-maps-sdk-questions/credentials-persistence-on-ios-invalid-token-error/m-p/1615913#M116</link>
    <description>&lt;BLOCKQUOTE&gt;&lt;HR /&gt;&lt;P&gt;&lt;FONT size="5"&gt;3. Ensure Authentication Flow Completes Before Token Use&lt;BR /&gt;&lt;/FONT&gt;&lt;BR /&gt;Make sure that:&lt;BR /&gt;- The user is signed in.&lt;BR /&gt;- The credential is valid.&lt;BR /&gt;- The SDK has had a chance to invoke the challenge handler (if needed).&lt;/P&gt;&lt;P&gt;If you call &lt;EM&gt;getToken()&lt;/EM&gt; too early (e.g., before the user signs in), it may fail.&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;HR /&gt;&lt;/BLOCKQUOTE&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;'getToken()' calls 'OAuthCredential.getTokenInfo()' internally. So, it should trigger the challenge handler regardless of when it is called.&lt;/P&gt;</description>
    <pubDate>Mon, 19 May 2025 09:47:12 GMT</pubDate>
    <dc:creator>EgorFedorov</dc:creator>
    <dc:date>2025-05-19T09:47:12Z</dc:date>
    <item>
      <title>Credentials persistence on iOS: 'Invalid token.' error in particular case</title>
      <link>https://community.esri.com/t5/flutter-maps-sdk-questions/credentials-persistence-on-ios-invalid-token-error/m-p/1614461#M108</link>
      <description>&lt;P&gt;Turning creds persistence on/off causes an exception.&lt;/P&gt;&lt;P&gt;Prerequisites:&lt;BR /&gt;- Set up OAuth2 sign in to ArcGIS Online.&lt;BR /&gt;- Set up request to secured resource ("&lt;A href="https://www.arcgis.com/sharing/rest/portals/self" target="_blank" rel="noopener"&gt;https://www.arcgis.com/sharing/rest/portals/self&lt;/A&gt;" in my case).&lt;BR /&gt;- For clean reproducing create new iOS emulator or use one where creds persistence was NOT enabled previously.&lt;/P&gt;&lt;P&gt;&lt;BR /&gt;Steps to reproduce:&lt;BR /&gt;1. Run app with persistence DISABLED. It works OK: shows prompt for login/password and performs authorized requests after that.&lt;BR /&gt;2. Close app and launch it with persistence ENABLED. It will fail with an exception:&lt;/P&gt;&lt;LI-CODE lang="markdown"&gt;ArcGISException: code=18006; Invalid token.; An invalid token was used to access https://www.arcgis.com/sharing/rest/oauth2/token.&lt;/LI-CODE&gt;&lt;P&gt;&lt;BR /&gt;3. Subsequent runs witn persistence DISABLED will work OK.&lt;BR /&gt;4. Subsequent runs witn persistence ENABLED will throw same exception again.&lt;/P&gt;&lt;P&gt;&lt;BR /&gt;At the same time, running app with enabled OR disabled persistence ONLY (without switching between modes) works well.&lt;BR /&gt;App reinstalling does not help.&lt;/P&gt;&lt;P&gt;&lt;BR /&gt;Code that enables persistence in my app is right from docs and is executed right before 'runApp()' call:&lt;/P&gt;&lt;LI-CODE lang="java"&gt;ArcGISEnvironment.authenticationManager.arcGISCredentialStore =
await ArcGISCredentialStore.initPersistentStore();&lt;/LI-CODE&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;Exception is thrown by 'oauthCredential.getTokenInfo()' call inside my internal class responsible for extracting OAuth2 token for my own server requests. Not sure why this is happening. I use all methods from SDK. Possibly, there is a call to 'oauth2/token' endpoint with outdated token, and server just returns an error instead of new token? Could you please advice something on this?&lt;/P&gt;&lt;P&gt;&lt;span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="creds-pers-token-issue.png" style="width: 400px;"&gt;&lt;img src="https://community.esri.com/t5/image/serverpage/image-id/132176i19453E03A2B25E21/image-size/medium?v=v2&amp;amp;px=400" role="button" title="creds-pers-token-issue.png" alt="creds-pers-token-issue.png" /&gt;&lt;/span&gt;&lt;/P&gt;&lt;P&gt; &lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&lt;BR /&gt;Tested via simulators:&lt;BR /&gt;- iPhone 15 w/ iOS 17.5&lt;BR /&gt;- iPhone 16 w/ iOS 18.4&lt;BR /&gt;- iPhone 16 Plus w/ iOS 18.4&lt;/P&gt;&lt;P&gt;Flutter 3.29.3, Dart 3.7.2, ArcGIS Flutter SDK 200.7.&lt;/P&gt;</description>
      <pubDate>Wed, 14 May 2025 09:18:07 GMT</pubDate>
      <guid>https://community.esri.com/t5/flutter-maps-sdk-questions/credentials-persistence-on-ios-invalid-token-error/m-p/1614461#M108</guid>
      <dc:creator>EgorFedorov</dc:creator>
      <dc:date>2025-05-14T09:18:07Z</dc:date>
    </item>
    <item>
      <title>Re: Credentials persistence on iOS: 'Invalid token.' error in particular case</title>
      <link>https://community.esri.com/t5/flutter-maps-sdk-questions/credentials-persistence-on-ios-invalid-token-error/m-p/1614639#M111</link>
      <description>&lt;P&gt;Thanks for the report&amp;nbsp;&amp;nbsp;&lt;a href="https://community.esri.com/t5/user/viewprofilepage/user-id/95128"&gt;@EgorFedorov&lt;/a&gt;&amp;nbsp;- the team is investigating if there is a bug or a workflow issue. We'll get back again when we've looked into it.&lt;/P&gt;</description>
      <pubDate>Wed, 14 May 2025 17:04:18 GMT</pubDate>
      <guid>https://community.esri.com/t5/flutter-maps-sdk-questions/credentials-persistence-on-ios-invalid-token-error/m-p/1614639#M111</guid>
      <dc:creator>JenMerritt</dc:creator>
      <dc:date>2025-05-14T17:04:18Z</dc:date>
    </item>
    <item>
      <title>Re: Credentials persistence on iOS: 'Invalid token.' error in particular case</title>
      <link>https://community.esri.com/t5/flutter-maps-sdk-questions/credentials-persistence-on-ios-invalid-token-error/m-p/1615213#M112</link>
      <description>&lt;P&gt;Thanks for the detailed breakdown and reproduction steps — that’s very helpful. Based on your description and the provided code, here’s what’s likely happening and how you can address it:&lt;/P&gt;&lt;P&gt;&lt;FONT size="5"&gt;1. Avoid Mixing Manual Token Handling with Challenge Handler&lt;BR /&gt;&lt;/FONT&gt;&lt;BR /&gt;You're currently using both:&lt;BR /&gt;- &lt;EM&gt;getToken()&lt;/EM&gt; to manually fetch tokens.&lt;BR /&gt;- &lt;EM&gt;handleArcGISAuthenticationChallenge()&lt;/EM&gt; to respond to SDK challenges.&lt;/P&gt;&lt;P&gt;This can lead to confusion and race conditions. Instead, have your challenge handler use your &lt;EM&gt;getToken()&lt;/EM&gt; method so that there is only ever a single call to &lt;EM&gt;OAuthUserCredential.create()&lt;/EM&gt;.&lt;/P&gt;&lt;P&gt;&lt;FONT size="5"&gt;2. Simplify Token Management&lt;BR /&gt;&lt;/FONT&gt;&lt;BR /&gt;Instead of using a &lt;EM&gt;CompleterList&lt;/EM&gt;, consider using a &lt;STRONG&gt;single shared &lt;EM&gt;Completer&amp;lt;String&amp;gt;?&lt;/EM&gt;&lt;/STRONG&gt;&amp;nbsp;to avoid redundant token requests:&lt;/P&gt;&lt;LI-CODE lang="javascript"&gt;Completer&amp;lt;String&amp;gt;? _tokenCompleter;

Future&amp;lt;String&amp;gt; getToken() {
if (_tokenCompleter != null) return _tokenCompleter!.future;

_tokenCompleter = Completer&amp;lt;String&amp;gt;();

OAuthUserCredential.create(configuration: _oAuthUserConfiguration)
.then((credential) =&amp;gt; credential.getTokenInfo())
.then((tokenInfo) {
_tokenCompleter!.complete(tokenInfo.accessToken);
})
.catchError((e, stackTrace) {
_tokenCompleter!.completeError(e, stackTrace);
});

return _tokenCompleter!.future;
}&lt;/LI-CODE&gt;&lt;P&gt;This ensures only one token request is active at a time.&lt;/P&gt;&lt;P&gt;&lt;FONT size="5"&gt;3. Ensure Authentication Flow Completes Before Token Use&lt;BR /&gt;&lt;/FONT&gt;&lt;BR /&gt;Make sure that:&lt;BR /&gt;- The user is signed in.&lt;BR /&gt;- The credential is valid.&lt;BR /&gt;- The SDK has had a chance to invoke the challenge handler (if needed).&lt;/P&gt;&lt;P&gt;If you call &lt;EM&gt;getToken()&lt;/EM&gt; too early (e.g., before the user signs in), it may fail.&lt;/P&gt;&lt;P&gt;&lt;FONT size="5"&gt;4. Manually Validate or Clear Invalid Credentials&lt;/FONT&gt;&lt;/P&gt;&lt;P&gt;If you're switching between persistent and non-persistent modes, consider &lt;STRONG&gt;validating or clearing credentials&lt;/STRONG&gt; before use:&lt;/P&gt;&lt;LI-CODE lang="javascript"&gt;final credential = ArcGISEnvironment
.authenticationManager.arcGISCredentialStore
.getCredential(uri: _oAuthUserConfiguration.portalUri);

if (credential is OAuthUserCredential) {
try {
await credential.getTokenInfo(); // Validate token
} catch (_) {
// Token is invalid, remove it
ArcGISEnvironment.authenticationManager.arcGISCredentialStore
.remove(credential: credential);
}
}&lt;/LI-CODE&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&lt;FONT size="6"&gt;Suggestion&lt;/FONT&gt;&lt;/P&gt;&lt;P&gt;If possible, please share a &lt;STRONG&gt;minimal reproducible example&lt;/STRONG&gt; (MRE) that isolates the issue. This will help confirm whether the problem lies in credential reuse, timing, or SDK behavior.&lt;/P&gt;&lt;P&gt;&lt;BR /&gt;&lt;FONT size="5"&gt;Summary:&lt;/FONT&gt;&lt;/P&gt;&lt;P&gt;- Let the SDK handle authentication via the challenge handler.&lt;BR /&gt;- Avoid mixing manual token fetching with SDK-managed flows.&lt;BR /&gt;- Use a single &lt;EM&gt;Completer&lt;/EM&gt; to manage token requests.&lt;BR /&gt;- Validate or clear credentials when switching persistence modes.&lt;BR /&gt;- Share a minimal example if the issue persists.&lt;/P&gt;</description>
      <pubDate>Thu, 15 May 2025 21:07:58 GMT</pubDate>
      <guid>https://community.esri.com/t5/flutter-maps-sdk-questions/credentials-persistence-on-ios-invalid-token-error/m-p/1615213#M112</guid>
      <dc:creator>HarishK</dc:creator>
      <dc:date>2025-05-15T21:07:58Z</dc:date>
    </item>
    <item>
      <title>Re: Credentials persistence on iOS: 'Invalid token.' error in particular case</title>
      <link>https://community.esri.com/t5/flutter-maps-sdk-questions/credentials-persistence-on-ios-invalid-token-error/m-p/1615901#M113</link>
      <description>&lt;P&gt;Thank you very much for your response.&lt;/P&gt;&lt;P&gt;I've spent whole day trying to figure out how to fix this.&lt;/P&gt;&lt;P&gt;For MRE, I've created new Flutter app from scratch, added 'arcgis_maps' package and executed simple '/self' request to AGOL. Surprisingly, it worked well. I've copied code from MRE to my project, and it failed with the same exception.&lt;/P&gt;&lt;P&gt;Then I've updated flutter SDK in 'pubspec.yaml' in project from&lt;/P&gt;&lt;DIV&gt;&lt;PRE&gt;&lt;SPAN&gt;environment&lt;/SPAN&gt;:&lt;BR /&gt;  &lt;SPAN&gt;sdk&lt;/SPAN&gt;: &lt;SPAN&gt;'&amp;gt;=3.7.0 &amp;lt;4.0.0'&lt;/SPAN&gt;&lt;/PRE&gt;&lt;/DIV&gt;&lt;P&gt;to&amp;nbsp;&lt;/P&gt;&lt;DIV&gt;&lt;PRE&gt;&lt;SPAN&gt;environment&lt;/SPAN&gt;:&lt;BR /&gt;  &lt;SPAN&gt;sdk&lt;/SPAN&gt;: ^3.7.2&lt;/PRE&gt;&lt;/DIV&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;After that:&lt;/P&gt;&lt;P&gt;- 'flutter clean' (several times)&lt;/P&gt;&lt;P&gt;- remove 'ios' folder and recreate it via 'flutter create . --platforms=ios'&lt;/P&gt;&lt;P&gt;- totally removed&amp;nbsp;'arcgis_maps' and installed again&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;Nothing helped. After weekend, I turn machine on and just re-run project. Surprisingly, it works well on all my simulators (listed above). So, I am totally not sure what fixed an issue. I guess, it should be some kind of update issue related to native project files.&lt;/P&gt;</description>
      <pubDate>Mon, 19 May 2025 09:07:15 GMT</pubDate>
      <guid>https://community.esri.com/t5/flutter-maps-sdk-questions/credentials-persistence-on-ios-invalid-token-error/m-p/1615901#M113</guid>
      <dc:creator>EgorFedorov</dc:creator>
      <dc:date>2025-05-19T09:07:15Z</dc:date>
    </item>
    <item>
      <title>Re: Credentials persistence on iOS: 'Invalid token.' error in particular case</title>
      <link>https://community.esri.com/t5/flutter-maps-sdk-questions/credentials-persistence-on-ios-invalid-token-error/m-p/1615907#M114</link>
      <description>&lt;P&gt;It would be great if we could continue this discussion.&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;BLOCKQUOTE&gt;&lt;HR /&gt;&lt;FONT size="5"&gt;1. Avoid Mixing Manual Token Handling with Challenge Handler&lt;BR /&gt;&lt;/FONT&gt;&lt;BR /&gt;You're currently using both:&lt;BR /&gt;- &lt;EM&gt;getToken()&lt;/EM&gt; to manually fetch tokens.&lt;BR /&gt;- &lt;EM&gt;handleArcGISAuthenticationChallenge()&lt;/EM&gt; to respond to SDK challenges.&lt;P&gt;This can lead to confusion and race conditions. Instead, have your challenge handler use your &lt;EM&gt;getToken()&lt;/EM&gt; method so that there is only ever a single call to &lt;EM&gt;OAuthUserCredential.create()&lt;/EM&gt;.&lt;/P&gt;&lt;HR /&gt;&lt;/BLOCKQUOTE&gt;&lt;P&gt;Well, I follow the rule: all &lt;STRONG&gt;actual&lt;/STRONG&gt; requests for token must be done by ArcGIS SDK. &lt;STRONG&gt;No one&lt;/STRONG&gt; auth request from my code. This is my intentional decision: SDK is the single source of truth, and it is responsible for all token-related operations (request, store, refresh). No manual call to smth like '&lt;A href="https://www.arcgis.com/sharing/rest/oauth2/token" target="_blank"&gt;https://www.arcgis.com/sharing/rest/oauth2/token&lt;/A&gt;' from my own code. Additionally, I am not always sure at which moment I need separate string token or just SDK-powered auth request.&lt;/P&gt;&lt;P&gt;Ideally, I want to achieve the following workflow:&lt;BR /&gt;- some object needs an access to secured resource&lt;BR /&gt;- it goes to SDK and asks for token&lt;BR /&gt;- SDK grabs token from internal storage or retrieves it from server and returns to object&lt;BR /&gt;- object uses it&lt;/P&gt;&lt;P&gt;Having this in mind, both 'getToken()' and 'handleArcGISAuthenticationChallenge()' call internal '_getCredential()' method that, in turn, calls 'OAuthUserCredential.create()'. Am I doing smth wrong?&lt;/P&gt;&lt;P&gt;&lt;BR /&gt;This worked well with 200.6. I was using this approach for about 4 month almost every day.&lt;/P&gt;</description>
      <pubDate>Mon, 19 May 2025 09:24:58 GMT</pubDate>
      <guid>https://community.esri.com/t5/flutter-maps-sdk-questions/credentials-persistence-on-ios-invalid-token-error/m-p/1615907#M114</guid>
      <dc:creator>EgorFedorov</dc:creator>
      <dc:date>2025-05-19T09:24:58Z</dc:date>
    </item>
    <item>
      <title>Re: Credentials persistence on iOS: 'Invalid token.' error in particular case</title>
      <link>https://community.esri.com/t5/flutter-maps-sdk-questions/credentials-persistence-on-ios-invalid-token-error/m-p/1615908#M115</link>
      <description>&lt;BLOCKQUOTE&gt;&lt;HR /&gt;&lt;P&gt;&lt;FONT size="5"&gt;2. Simplify Token Management&lt;BR /&gt;&lt;/FONT&gt;&lt;BR /&gt;Instead of using a &lt;EM&gt;CompleterList&lt;/EM&gt;, consider using a &lt;STRONG&gt;single shared &lt;EM&gt;Completer&amp;lt;String&amp;gt;?&lt;/EM&gt;&lt;/STRONG&gt;&amp;nbsp;to avoid redundant token requests:&lt;/P&gt;&lt;/BLOCKQUOTE&gt;&lt;LI-CODE lang="javascript"&gt;Completer&amp;lt;String&amp;gt;? _tokenCompleter;

Future&amp;lt;String&amp;gt; getToken() {
if (_tokenCompleter != null) return _tokenCompleter!.future;

_tokenCompleter = Completer&amp;lt;String&amp;gt;();

OAuthUserCredential.create(configuration: _oAuthUserConfiguration)
.then((credential) =&amp;gt; credential.getTokenInfo())
.then((tokenInfo) {
_tokenCompleter!.complete(tokenInfo.accessToken);
})
.catchError((e, stackTrace) {
_tokenCompleter!.completeError(e, stackTrace);
});

return _tokenCompleter!.future;
}&lt;/LI-CODE&gt;&lt;P&gt;This ensures only one token request is active at a time.&lt;/P&gt;&lt;HR /&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;Looks like this won't work when token becomes invalid.&lt;/P&gt;&lt;P&gt;Imagine that after ~1h 'getToken()' is called again. In this case previously requested token is outdated (its lifetime is about 30 mins, but it depends). But '_tokenCompleter' is still not null. Moreover, '_tokenCompleter.future' is already fulfilled with old token. As a result, this invalid token will be returned.&lt;/P&gt;&lt;P&gt;I definitely don't want to check manually if token is valid or not. I want SDK to do this for me. It already implements (or will implement in future) all possible auth algorithms, not OAuth only: IWA, social, whatever.&lt;/P&gt;&lt;P&gt;So, this drives my current approach:&lt;BR /&gt;- 1 getToken() call = 1 NEW future returned&lt;BR /&gt;- 1 call for token to SDK = 1 list of completers (token waiters queue). All completers in this list are completed with result or error simultaneously, after that list is cleared.&lt;/P&gt;&lt;P&gt;Does this approach look correct?&lt;/P&gt;</description>
      <pubDate>Mon, 19 May 2025 09:29:05 GMT</pubDate>
      <guid>https://community.esri.com/t5/flutter-maps-sdk-questions/credentials-persistence-on-ios-invalid-token-error/m-p/1615908#M115</guid>
      <dc:creator>EgorFedorov</dc:creator>
      <dc:date>2025-05-19T09:29:05Z</dc:date>
    </item>
    <item>
      <title>Re: Credentials persistence on iOS: 'Invalid token.' error in particular case</title>
      <link>https://community.esri.com/t5/flutter-maps-sdk-questions/credentials-persistence-on-ios-invalid-token-error/m-p/1615913#M116</link>
      <description>&lt;BLOCKQUOTE&gt;&lt;HR /&gt;&lt;P&gt;&lt;FONT size="5"&gt;3. Ensure Authentication Flow Completes Before Token Use&lt;BR /&gt;&lt;/FONT&gt;&lt;BR /&gt;Make sure that:&lt;BR /&gt;- The user is signed in.&lt;BR /&gt;- The credential is valid.&lt;BR /&gt;- The SDK has had a chance to invoke the challenge handler (if needed).&lt;/P&gt;&lt;P&gt;If you call &lt;EM&gt;getToken()&lt;/EM&gt; too early (e.g., before the user signs in), it may fail.&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;HR /&gt;&lt;/BLOCKQUOTE&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;'getToken()' calls 'OAuthCredential.getTokenInfo()' internally. So, it should trigger the challenge handler regardless of when it is called.&lt;/P&gt;</description>
      <pubDate>Mon, 19 May 2025 09:47:12 GMT</pubDate>
      <guid>https://community.esri.com/t5/flutter-maps-sdk-questions/credentials-persistence-on-ios-invalid-token-error/m-p/1615913#M116</guid>
      <dc:creator>EgorFedorov</dc:creator>
      <dc:date>2025-05-19T09:47:12Z</dc:date>
    </item>
    <item>
      <title>Re: Credentials persistence on iOS: 'Invalid token.' error in particular case</title>
      <link>https://community.esri.com/t5/flutter-maps-sdk-questions/credentials-persistence-on-ios-invalid-token-error/m-p/1616099#M117</link>
      <description>&lt;P&gt;&lt;SPAN&gt;Could you please provide a complete working example of the problematic code? This will help us reproduce the issue on our end.&lt;/SPAN&gt;&lt;/P&gt;</description>
      <pubDate>Mon, 19 May 2025 16:56:20 GMT</pubDate>
      <guid>https://community.esri.com/t5/flutter-maps-sdk-questions/credentials-persistence-on-ios-invalid-token-error/m-p/1616099#M117</guid>
      <dc:creator>HarishK</dc:creator>
      <dc:date>2025-05-19T16:56:20Z</dc:date>
    </item>
  </channel>
</rss>

