Skip to content

feat: surface IPSIE session_expiry claim across Android, iOS and web#904

Open
utkrishtsahu wants to merge 2 commits into
mainfrom
feat/ipse-session-expiry
Open

feat: surface IPSIE session_expiry claim across Android, iOS and web#904
utkrishtsahu wants to merge 2 commits into
mainfrom
feat/ipse-session-expiry

Conversation

@utkrishtsahu

@utkrishtsahu utkrishtsahu commented Jul 23, 2026

Copy link
Copy Markdown
Contributor
  • All new/changed/fixed functionality is covered by tests (or N/A)
  • I have added documentation for all new/changed functionality (or N/A)

📋 Changes

Adds support for the IPSIE session_expiry claim — an absolute Unix-seconds ceiling asserted by an upstream IdP (over an enterprise connection with "Use ID Token for Session Expiry" / id_token_session_expiry_supported: true enabled). The claim acts as a hard ceiling on the local session: the app session can never outlive the upstream IdP session.

Enforcement itself lives in the native SDKs; this change bumps to the versions that ship it, surfaces the value through the Dart Credentials model, and carries it across the platform-channel boundary on all three platforms.

Public API

  • Credentials (auth0_flutter_platform_interface): new optional, nullable DateTime? sessionExpiry field, wired through the constructor, fromMap, and toMap. Additive and non-breaking — null means "no ceiling" and is never treated as expired.
    final credentials = await auth0.credentialsManager.credentials();
    final sessionExpiry = credentials.sessionExpiry; // null when the claim is absent
    if (sessionExpiry != null) {
      print('Upstream IdP session ends at: $sessionExpiry');
    }
  • Once the ceiling passes, the native SDK treats the stored credentials as expired and skips refresh, so credentials() raises the existing CredentialsManagerException (isNoCredentialsFound) — no new error type or handling code required.

Serialization

  • Darwin (iOS/macOS): Extensions.swift decodes session_expiry (Unix seconds → ISO-8601) in Credentials.asDictionary(); new sessionExpiry case in Properties.swift.
  • Android: new shared Credentials.toMap() extension (CredentialsExtensions.kt) reading the claim from user.getExtraInfo(), used by the login, get, and renew handlers (deduplicates three copy-pasted maps).
  • Web: credentials_extension.dart decodes the claim from the ID token.

Dependency bumps (minor line that introduced the feature, not the next major)

  • Auth0.swift → 2.24.1 (all podspecs + Package.swift)
  • auth0-spa-js → 2.22.0 (example web/index.html)
  • Auth0.Android already at 3.21.0 (≥ 3.20.0) — no change needed

Docs: README.md note + new "Session expiry from an upstream IdP" section in EXAMPLES.md.

📎 References

SDK-10259

🎯 Testing

Automated (added in this PR)

  • Platform interface (credentials_test.dart): sessionExpiry present/absent via fromMap; ISO-8601 UTC output and null omission via toMap.
  • Web (credentials_extension_test.dart): claim decoded from a signed test token; null when absent.
  • Android (GetCredentialsRequestHandlerTest / RenewCredentialsRequestHandlerTest): claim presence/absence, and preservation across renew (a refresh must not extend the ceiling); JwtTestUtils extended with numeric claims.

Run:

# platform interface
cd auth0_flutter_platform_interface && flutter test test/credentials_test.dart
# web
cd auth0_flutter && flutter test test/web/extensions/credentials_extension_test.dart --platform chrome
# android
cd auth0_flutter/example/android && ./gradlew :auth0_flutter:testDebugUnitTest

Manual (end-to-end)

  1. Configure an enterprise connection with an upstream IdP and enable "Use ID Token for Session Expiry" (id_token_session_expiry_supported: true).
  2. Log in on iOS, Android, and web; confirm credentials.sessionExpiry is non-null and matches the session_expiry claim in the ID token.
  3. Call renewCredentials() and confirm the ceiling is unchanged (not pushed later).
  4. Wait for the ceiling to pass, then call credentials() — confirm it raises CredentialsManagerException with isNoCredentialsFound, and that a fresh login succeeds.

Summary by CodeRabbit

  • New Features

    • Added support for upstream identity provider session expiry ceilings.
    • Credentials now expose an optional sessionExpiry timestamp when provided.
    • Session expiry is preserved across login, retrieval, renewal, and web authentication flows.
  • Documentation

    • Added guidance for configuring upstream session expiry and handling expired sessions.
    • Documented the web requirement for Auth0 SPA SDK 2.22.0 or later.
  • Bug Fixes

    • Improved consistency of credential data across Android, iOS, macOS, and web platforms.

@coderabbitai

coderabbitai Bot commented Jul 23, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

Adds Credentials.sessionExpiry support across the Dart, Android, iOS, macOS, and web implementations. ID-token session_expiry claims are converted to UTC values, serialized through credential responses, tested, and documented.

Changes

Upstream IdP session expiry

Layer / File(s) Summary
Credential session expiry contract
auth0_flutter_platform_interface/lib/src/credentials.dart, auth0_flutter_platform_interface/test/credentials_test.dart, auth0_flutter/darwin/.../Properties.swift
Adds optional Credentials.sessionExpiry support with UTC map serialization and deserialization.
Android credential propagation
auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/..., auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/...
Centralizes Android credential mapping, extracts numeric session_expiry, and covers login, retrieval, and renewal responses.
iOS, macOS, and web extraction
auth0_flutter/darwin/..., auth0_flutter/ios/..., auth0_flutter/macos/..., auth0_flutter/lib/src/web/..., auth0_flutter/test/web/...
Extracts the claim on native and web platforms, updates Auth0 dependencies to 2.24.1, and adds web tests.
Session expiry documentation
auth0_flutter/EXAMPLES.md, auth0_flutter/README.md
Documents the hard session ceiling, login handling, field access, and the auth0-spa-js 2.22.0+ requirement.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant IdToken
  participant PlatformSDK
  participant CredentialsMapper
  participant FlutterCredentials
  IdToken->>PlatformSDK: provide session_expiry claim
  PlatformSDK->>CredentialsMapper: extract and convert Unix seconds
  CredentialsMapper->>FlutterCredentials: serialize sessionExpiry
Loading

Suggested reviewers: sanchitmehtagit

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main feature: surfacing the session_expiry claim across Android, iOS/macOS, and web.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/ipse-session-expiry

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@auth0_flutter_platform_interface/lib/src/credentials.dart`:
- Around line 57-58: Update the shared Credentials documentation near the
expiresAt description to refer to the “underlying platform SDK” rather than only
the native SDK, and explicitly distinguish native SDK expiration enforcement
from web renewal enforcement handled by auth0-spa-js in the web credentials
extension.
- Around line 91-93: Update the sessionExpiry conversion in the credentials
parsing flow to validate result['sessionExpiry'] with an is String check before
parsing or casting. Add a private helper if appropriate that returns null for
null, parses accepted strings to UTC DateTime, and throws a clear
FormatException for other value types; use this helper from the sessionExpiry
assignment.

In
`@auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/CredentialsExtensions.kt`:
- Around line 15-17: Update Credentials.toMap and the related
Instant.ofEpochSecond serialization path to avoid java.time APIs on minSdk 21,
or enable and configure core-library desugaring in the Android build settings.
Ensure credential date formatting/storage remains unchanged across supported API
levels, and apply the same compatibility fix to both referenced call sites.

In `@auth0_flutter/lib/src/web/extensions/credentials_extension.dart`:
- Around line 20-26: Update the sessionExpiryClaim local in the credentials
parsing flow to explicitly use the Object? type instead of relying on dynamic
inference from claims['session_expiry']; retain the existing is num guard and
DateTime conversion unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 83e4b42d-350f-4113-bd36-da4a951e8476

📥 Commits

Reviewing files that changed from the base of the PR and between 51d4a78 and a5b14b8.

⛔ Files ignored due to path filters (1)
  • auth0_flutter/example/web/index.html is excluded by !**/example/**
📒 Files selected for processing (20)
  • auth0_flutter/EXAMPLES.md
  • auth0_flutter/README.md
  • auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/Auth0FlutterPlugin.kt
  • auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/CredentialsExtensions.kt
  • auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/credentials_manager/GetCredentialsRequestHandler.kt
  • auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/credentials_manager/RenewCredentialsRequestHandler.kt
  • auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/web_auth/LoginWebAuthRequestHandler.kt
  • auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/JwtTestUtils.kt
  • auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/request_handlers/credentials_manager/GetCredentialsRequestHandlerTest.kt
  • auth0_flutter/android/src/test/kotlin/com/auth0/auth0_flutter/request_handlers/credentials_manager/RenewCredentialsRequestHandlerTest.kt
  • auth0_flutter/darwin/auth0_flutter.podspec
  • auth0_flutter/darwin/auth0_flutter/Package.swift
  • auth0_flutter/darwin/auth0_flutter/Sources/auth0_flutter/Extensions.swift
  • auth0_flutter/darwin/auth0_flutter/Sources/auth0_flutter/Properties.swift
  • auth0_flutter/ios/auth0_flutter.podspec
  • auth0_flutter/lib/src/web/extensions/credentials_extension.dart
  • auth0_flutter/macos/auth0_flutter.podspec
  • auth0_flutter/test/web/extensions/credentials_extension_test.dart
  • auth0_flutter_platform_interface/lib/src/credentials.dart
  • auth0_flutter_platform_interface/test/credentials_test.dart

Comment on lines +57 to +58
/// underlying native SDK treats the credentials as expired once this time is
/// reached and will not renew them past it, regardless of [expiresAt].

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Document web enforcement separately.

These shared Credentials docs say the underlying native SDK enforces the ceiling, but auth0_flutter/lib/src/web/extensions/credentials_extension.dart relies on auth0-spa-js for web renewal. Use “underlying platform SDK” and distinguish native enforcement from web enforcement.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@auth0_flutter_platform_interface/lib/src/credentials.dart` around lines 57 -
58, Update the shared Credentials documentation near the expiresAt description
to refer to the “underlying platform SDK” rather than only the native SDK, and
explicitly distinguish native SDK expiration enforcement from web renewal
enforcement handled by auth0-spa-js in the web credentials extension.

Comment on lines +91 to +93
sessionExpiry: result['sessionExpiry'] == null
? null
: DateTime.parse(result['sessionExpiry'] as String).toUtc(),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Guard the dynamic value before casting.

A non-null, non-String value reaches as String and throws at the credential boundary. Validate with an is String check and fail explicitly for malformed values rather than using an unchecked cast.

As per path instructions, Dart code must use is checks or pattern matching before casts.

Suggested guard
-        sessionExpiry: result['sessionExpiry'] == null
-            ? null
-            : DateTime.parse(result['sessionExpiry'] as String).toUtc(),
+        sessionExpiry: _parseSessionExpiry(result['sessionExpiry']),

Add a private helper that returns null for null, accepts only String, and throws a clear FormatException otherwise.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@auth0_flutter_platform_interface/lib/src/credentials.dart` around lines 91 -
93, Update the sessionExpiry conversion in the credentials parsing flow to
validate result['sessionExpiry'] with an is String check before parsing or
casting. Add a private helper if appropriate that returns null for null, parses
accepted strings to UTC DateTime, and throws a clear FormatException for other
value types; use this helper from the sessionExpiry assignment.

Source: Path instructions

Comment on lines +15 to +17
fun Credentials.toMap(): Map<String, Any?> {
val scopes = this.scope?.split(" ") ?: listOf()
val formattedDate = this.expiresAt.toInstant().toString()

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -eu

rg -n \
  'coreLibraryDesugaring|isCoreLibraryDesugaringEnabled|compileOptions|minSdk' \
  auth0_flutter/android -g '*.gradle' -g '*.gradle.kts' -g '*.properties'

rg -n 'java\.time\.Instant|\.toInstant\(' \
  auth0_flutter/android/src/main

Repository: auth0/auth0-flutter

Length of output: 2740


🏁 Script executed:

#!/bin/bash
set -eu

printf '--- build files ---\n'
git ls-files 'auth0_flutter/android/*.gradle*' 'auth0_flutter/android/settings.gradle*' 'auth0_flutter/android/gradle.properties' | sort | xargs -r -n1 sh -c 'echo "### $0"; cat -n "$0"'

printf '\n--- relevant Kotlin snippets ---\n'
for f in auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/CredentialsExtensions.kt \
         auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/MfaExtensions.kt \
         auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/credentials_manager/SaveCredentialsRequestHandler.kt \
         auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/credentials_manager/GetApiCredentialsRequestHandler.kt \
         auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/api/LoginWithSMSCodeApiRequestHandler.kt \
         auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/api/LoginWithOtpApiRequestHandler.kt \
         auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/api/RenewApiRequestHandler.kt \
         auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/api/PasspassCredentialExchangeApiRequestHandler.kt \
         auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/api/LoginApiRequestHandler.kt \
         auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/api/CustomTokenExchangeApiRequestHandler.kt \
         auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/api/LoginWithEmailCodeApiRequestHandler.kt \
         auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/api/PasswordlessLoginWithOtpApiRequestHandler.kt
do
  if [ -f "$f" ]; then
    echo "### $f"
    wc -l "$f"
    sed -n '1,120p' "$f" | cat -n
  fi
done

printf '\n--- occurrences summary ---\n'
rg -n 'Date|toInstant|Instant' auth0_flutter/android/src/main/kotlin

Repository: auth0/auth0-flutter

Length of output: 248


🏁 Script executed:

#!/bin/bash
set -eu

printf '%s\n' '--- build files ---'
git ls-files 'auth0_flutter/android/*.gradle*' 'auth0_flutter/android/settings.gradle*' 'auth0_flutter/android/gradle.properties' | sort | xargs -r -n1 sh -c 'echo "### $0"; cat -n "$0"'

printf '%s\n' ''
printf '%s\n' '--- relevant JavaTime occurrences ---'
for f in auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/CredentialsExtensions.kt \
         auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/MfaExtensions.kt \
         auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/credentials_manager/SaveCredentialsRequestHandler.kt \
         auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/credentials_manager/GetApiCredentialsRequestHandler.kt \
         auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/api/LoginWithSMSCodeApiRequestHandler.kt \
         auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/api/LoginWithOtpApiRequestHandler.kt \
         auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/api/RenewApiRequestHandler.kt \
         auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/api/PasskeyCredentialExchangeApiRequestHandler.kt \
         auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/api/LoginApiRequestHandler.kt \
         auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/api/CustomTokenExchangeApiRequestHandler.kt \
         auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/api/LoginWithEmailCodeApiRequestHandler.kt \
         auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/request_handlers/api/PasswordlessLoginWithOtpApiRequestHandler.kt
do
  if [ -f "$f" ]; then
    echo "### $f"
    wc -l "$f"
    sed -n '1,120p' "$f" | cat -n
  fi
done

printf '%s\n' ''
printf '%s\n' '--- occurrences summary ---'
rg -n 'Date|toInstant|Instant' auth0_flutter/android/src/main/kotlin || true

Repository: auth0/auth0-flutter

Length of output: 47531


Remove minSdk 21 Java Time calls or enable core-library desugaring.

Credentials.toMap() calls Date.toInstant() and java.time.Instant.ofEpochSecond() for credential serialization, but build.gradle only sets minSdkVersion 21 and has no core-library desugaring configured. Add coreLibraryDesugaringEnabled = true or replace these with API-21-safe formatting/storage paths.

Also applies to: 36-38

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@auth0_flutter/android/src/main/kotlin/com/auth0/auth0_flutter/CredentialsExtensions.kt`
around lines 15 - 17, Update Credentials.toMap and the related
Instant.ofEpochSecond serialization path to avoid java.time APIs on minSdk 21,
or enable and configure core-library desugaring in the Android build settings.
Ensure credential date formatting/storage remains unchanged across supported API
levels, and apply the same compatibility fix to both referenced call sites.

Source: Path instructions

Comment on lines +20 to +26
final sessionExpiryClaim = claims['session_expiry'];
final sessionExpiry = sessionExpiryClaim is num
? DateTime.fromMillisecondsSinceEpoch(
sessionExpiryClaim.toInt() * 1000,
isUtc: true,
)
: null;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Locate and inspect the relevant Dart file and any relevant project config.
printf '--- files ---\n'
git ls-files | rg '(^|/)credentials_extension\.dart$|auth0_flutter/|analysis_options' || true

printf '\n--- credentials_extension outline ---\n'
ast-grep outline auth0_flutter/lib/src/web/extensions/credentials_extension.dart || true

printf '\n--- credentials_extension content ---\n'
cat -n auth0_flutter/lib/src/web/extensions/credentials_extension.dart

printf '\n--- find claims parameter declarations/imports ---\n'
rg -n "credentials_extension|sessionExpiryClaim|session_expiry|claims" auth0_flutter/lib/src/web -S || true

printf '\n--- analyze options ---\n'
fd -a 'analysis_options.*yaml|pubspec.yaml' auth0_flutter | sort | xargs -r sh -c 'echo "### $1"; cat -n "$1"' sh {}

Repository: auth0/auth0-flutter

Length of output: 248


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- files ---'
git ls-files | rg '(^|/)credentials_extension\.dart$|^auth0_flutter/|analysis_options' || true

printf '%s\n' '--- credentials_extension content ---'
if [ -f auth0_flutter/lib/src/web/extensions/credentials_extension.dart ]; then
  cat -n auth0_flutter/lib/src/web/extensions/credentials_extension.dart
else
  fd -a 'credentials_extension.dart' . | sed -n '1,20p'
fi

printf '%s\n' '--- find claims/session_expiry usages ---'
rg -n "credentials_extension|sessionExpiryClaim|session_expiry|claims\[" auth0_flutter/lib/src/web -S || true

printf '%s\n' '--- analyze/config files ---'
fd -a 'analysis_options.*yaml|pubspec.yaml' . | sort | sed -n '1,60p' | while IFS= read -r f; do
  echo "### $f"
  cat -n "$f" | sed -n '1,220p'
done

Repository: auth0/auth0-flutter

Length of output: 50375


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' "--- relevant file contents ---"
if [ -f auth0_flutter/lib/src/web/extensions/credentials_extension.dart ]; then
  cat -n auth0_flutter/lib/src/web/extensions/credentials_extension.dart
else
  file="$(fd 'credentials_extension.dart' . | head -n 1 || true)"
  if [ -n "${file:-}" ]; then cat -n "$file"; fi
fi

printf '%s\n' "--- analyzer config for infer_dynamic ---"
cat -n auth0_flutter/analysis_options.yaml | sed -n '1,220p' | rg -n "strict-|explicit-callback-types|static" -C 3 || true

printf '%s\n' "--- Dart availability and static type probe if tool exists ---"
if command -v dart >/dev/null 2>&1; then
  tmp="$(mktemp -d)"
  cat > "$tmp/strict_inference.dart" <<'HEREDOC'
void main() {
  final claims = <String, Object?>{};
  final sessionExpiryClaim = claims['session_expiry'];
  final sessionExpiry = sessionExpiryClaim is num
      ? DateTime.fromMillisecondsSinceEpoch(sessionExpiryClaim.toInt() * 1000, isUtc: true)
      : null;
  print(sessionExpiry);
}
HEREDOC
  dart analyze --strict-inference "$tmp/strict_inference.dart" 2>&1 || true
else
  echo 'dart command not available'
fi

Repository: auth0/auth0-flutter

Length of output: 2671


Avoid inferred dynamic for the JWT claim.

This local is typed dynamic because of strict inference from the map lookup. Type it as Object?; the existing is num guard still promotes it safely.

Proposed fix
-    final sessionExpiryClaim = claims['session_expiry'];
+    final Object? sessionExpiryClaim = claims['session_expiry'];
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
final sessionExpiryClaim = claims['session_expiry'];
final sessionExpiry = sessionExpiryClaim is num
? DateTime.fromMillisecondsSinceEpoch(
sessionExpiryClaim.toInt() * 1000,
isUtc: true,
)
: null;
final Object? sessionExpiryClaim = claims['session_expiry'];
final sessionExpiry = sessionExpiryClaim is num
? DateTime.fromMillisecondsSinceEpoch(
sessionExpiryClaim.toInt() * 1000,
isUtc: true,
)
: null;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@auth0_flutter/lib/src/web/extensions/credentials_extension.dart` around lines
20 - 26, Update the sessionExpiryClaim local in the credentials parsing flow to
explicitly use the Object? type instead of relying on dynamic inference from
claims['session_expiry']; retain the existing is num guard and DateTime
conversion unchanged.

Source: Path instructions

* UTC string. Returns `null` when the claim is absent or not numeric.
*/
private fun Credentials.sessionExpiryIso(): String? {
val claim = user.getExtraInfo()["session_expiry"] as? Number ?: return null

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

credentials exposes sessionExpiresAt can we not use it directly?

Comment thread auth0_flutter/EXAMPLES.md
}
```

> ⚠️ **Upgrade note:** once this feature is enabled on your connection, `credentials()` can raise a "no credentials" error for a user who was previously logged in, when the ceiling is reached. If your app assumed `credentials()` always resolves after login, make sure it handles this case (it already does if you catch `CredentialsManagerException` as shown above).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we mention IPSIE as EA?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants