Skip to content

Getting started

package:oidc

This document shows how to setup package:oidc for the first time.

you can check the example project for the final result.

after following this document, you can check the Usage Document

Adding dependencies

dart pub add oidc oidc_default_store oidc_core

every platform you support has its own configuration and set up.

Native browser handling is first-party on every platform (no third-party auth SDK):

  • AndroidAuth Tab, falling back to Chrome Custom Tabs (requires minSdk 23+).
  • iOSASWebAuthenticationSession (requires iOS 13+).
  • macOSASWebAuthenticationSession (requires macOS 10.15+).

we also rely on flutter_secure_storage in our oidc_default_store implementation, to encrypt the stored access tokens.

Android

Redirect handling (Auth Tab / Chrome Custom Tabs)

oidc_android opens the system browser via Auth Tab (falling back to Chrome Custom Tabs) and ships its own transparent redirect receiver (OidcRedirectActivity), so you only declare the scheme of your redirect_uri with a single manifest placeholder.

Auth Tab returns the redirect through the Activity Result API, which needs both Chrome 137+ and a host activity that extends ComponentActivity — that is FlutterFragmentActivity, not the default FlutterActivity. Anything else — another browser, or the default host — degrades to a plain Custom Tab, and the redirect is caught by the receiver's intent-filter instead. The placeholder below is what wires that receiver up, so it is required for login to work.

go to android/app/build.gradle, and add the following under defaultConfig:

defaultConfig {
    applicationId "com.my.app"
-   minSdkVersion flutter.minSdkVersion
+   minSdkVersion 23
    targetSdkVersion flutter.targetSdkVersion
    versionCode flutterVersionCode.toInteger()
    versionName flutterVersionName
+   manifestPlaceholders += [
+       'oidcRedirectScheme': 'com.my.app'
+   ]
}

minSdkVersion must be 23 or higher. oidc_android depends on androidx.browser:browser:1.10.0, which declares minSdk 23; a lower value in your app fails the manifest merge at build time. If you are upgrading from oidc_android 1.0.1 or earlier, this is the one change that can break your build — its floor was 21. replace com.my.app with the scheme of your redirect_uri (a reverse-DNS scheme you own, per RFC 8252 §7.1); your redirect_uri then looks like com.my.app://oauth2redirect.

  • You do not add any <intent-filter>, launchMode, or taskAffinity to MainActivity — the plugin handles redirect delivery.

IMPORTANT NOTE

if your applicationId/scheme contains an underscore (_), replace it with a dot (.) in the oidcRedirectScheme (schemes can't contain underscores).

Upgrading from a flutter_appauth-based setup? Delete the old appAuthRedirectScheme placeholder and any redirect <intent-filter> you hand-added to MainActivitypackage:oidc no longer depends on flutter_appauth on any platform, so they are no longer used.

HTTPS redirect (App Links)? A https:// redirect_uri additionally needs a verified Android App Link (host an assetlinks.json). Custom schemes need no verification and are the simpler choice for most apps.

flutter_secure_storage setup

Source

  1. flutter_secure_storage needs minSdkVersion >= 18, which the 23 required above already satisfies — no further change if you set it.
    defaultConfig {   
    
        applicationId "com.my_app"
    -   minSdkVersion flutter.minSdkVersion
    +   minSdkVersion 23
        targetSdkVersion flutter.targetSdkVersion
        versionCode flutterVersionCode.toInteger()
        versionName flutterVersionName
        manifestPlaceholders += [
            'oidcRedirectScheme': 'com.my.app'
        ]
    }
    
  2. Disable backup:

    1. Create the following file in android\app\src\main\res\xml\backup_rules.xml

      <?xml version="1.0" encoding="utf-8"?>
      <full-backup-content>
              <exclude domain="sharedpref" path="FlutterSecureStorage"/>
      </full-backup-content>
      

    2. Create the following file in android\app\src\main\res\xml\data_extraction_rules.xml

      <?xml version="1.0" encoding="utf-8"?>
      <data-extraction-rules>
          <cloud-backup>
              <exclude domain="sharedpref" path="FlutterSecureStorage"/>
          </cloud-backup>
      </data-extraction-rules>
      

    3. in android\app\src\main\AndroidManifest.xml add the following attributes to application tag:
      <application
              android:label="example"
              android:name="${applicationName}"
              android:icon="@mipmap/ic_launcher"
      +   android:fullBackupContent="@xml/backup_rules"
      +   android:dataExtractionRules="@xml/data_extraction_rules"
              >
      

Enable MultiDex

Source

just do flutter run from your terminal (not IDE) once, and it will ask you to enable it (press y).

iOS

Redirect handling (ASWebAuthenticationSession)

oidc_darwin (iOS) uses the system ASWebAuthenticationSession, which registers your redirect_uri scheme at runtime. You do not need a CFBundleURLTypes / CFBundleURLSchemes entry in ios/Info.plist for the OIDC redirect, and you do not add any third-party SDK.

Requirements:

  • iOS 13.0+ — set the deployment target accordingly in Xcode and in ios/Podfile (platform :ios, '13.0' or higher).
  • For an https/Universal-Link redirect_uri (optional, iOS 17.4+), your app must declare an Associated Domains entitlement. Custom schemes need no entitlement and are the simpler choice.

macOS

Redirect handling (ASWebAuthenticationSession)

oidc_darwin (macOS) uses the system ASWebAuthenticationSession (the same first-party approach as iOS — no third-party SDK), which registers your redirect_uri scheme at runtime. You do not need a CFBundleURLTypes / CFBundleURLSchemes entry in macos/Info.plist for the OIDC redirect.

Requirements:

  • macOS 10.15+ — set the deployment target accordingly in Xcode and in macos/Podfile (platform :osx, '10.15' or higher).

App Sandbox network entitlement (macOS)

macOS runs under the App Sandbox, which blocks outbound network by default. The OIDC flow needs network access, so add the network-client entitlement to both macos/Runner/DebugProfile.entitlements and macos/Runner/Release.entitlements:

<key>com.apple.security.network.client</key>
<true/>

(For signed/notarized distribution, the Hardened Runtime is required and is compatible with these entitlements.)

flutter_secure_storage setup for macos

Source

You need to add Keychain Sharing as capability to your macOS runner. To achieve this, please add the following in both your macos/Runner/DebugProfile.entitlements and macos/Runner/Release.entitlements (you need to change both files).

<key>keychain-access-groups</key>
<array/>

Web

for web, you need a separate html page to be delivered with your app, which will handle oidc-related requests.

you can get the page from the example project:

redirect.html

it doesn't matter where you put the page and what you call it, but it MUST be delivered from your redirect_uri

for example, here is a common configuration using this page:

final htmlPageLinkDevelopment = Uri.parse('http://localhost:22433/redirect.html');
final htmlPageLinkProduction = Uri.parse('https://mywebsite.com/redirect.html');

final htmlPageLink = kDebugMode ? htmlPageLinkDevelopment : htmlPageLinkProduction;

final redirectUri = htmlPageLink;
final postLogoutRedirectUri = htmlPageLink;
final frontChannelLogoutUri = htmlPageLink.replace(
    queryParameters: {
        ...htmlPageLink.queryParameters,
        'requestType': 'front-channel-logout'
    }
);
Note how frontChannelLogoutUri needs requestType=front-channel-logout for the page to know the request type.

you will have to register these urls with the openid provider first, depending on your configuration.

also the html page is completely customizable, but it's preferred to leave the javascript part as is, since it's well-integrated with the plugin. All user-visible copy lives in a single messages object near the top of the script and is safe to translate.

How the page talks to the app

The page and the app exchange messages over a BroadcastChannel:

  • on load, the page posts the incoming redirect to the app as a small JSON envelope: {"v":2,"type":"redirect","uri":"<full redirect url>"};
  • once the app has processed it (the token exchange finished — or failed), the app posts an acknowledgement back: {"v":2,"type":"ack","status":"ok"|"error","message":"<short message>"}.

The page only shows a success state after an ok ack — so it no longer claims "Operation Successful" when the app-side exchange actually failed. It shows an error state on an error ack, or when the provider returned an error directly in the redirect (error/error_description/error_uri, per RFC 6749 §4.1.2.1). If no ack arrives within ~10s (e.g. an older app version that never acks), or the browser refuses to close a tab the script didn't open (email-link tabs), it falls back to a neutral "you can now close this tab" state.

The app still accepts the older bare-URL message, so an outdated copy of the page keeps working after you upgrade the package. The reverse does not hold: this v2 page needs the matching (v2-aware) package version.

Upgrading

redirect.html is copied into your own project, not shipped by the package, so flutter pub upgrade never updates it. When you upgrade oidc, re-copy the page from the example so the app and the page stay on the same wire version.

Troubleshooting

  • The page never loads (blank tab, or your host/proxy's 502/504). None of the javascript above can run if the redirect_uri doesn't actually serve this page. Make sure your host or reverse proxy serves redirect.html at the exact redirect_uri path in every environment. While that tab is broken the app receives nothing, so the pending login stays unresolved — return to the app to cancel it (or let it time out) and retry once the page is served correctly.

Read more

flutter_secure_storage setup for web

Source

Flutter Secure Storage uses an experimental implementation using WebCrypto. Use at your own risk at this time. Feedback welcome to improve it. The intent is that the browser is creating the private key, and as a result, the encrypted strings in local_storage are not portable to other browsers or other machines and will only work on the same domain.

! It is VERY important that you have HTTP Strict Forward Secrecy enabled and the proper headers applied to your responses or you could be subject to a javascript hijack.

Please see:

  • https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security
  • https://www.netsparker.com/blog/web-security/http-security-headers/

Windows

Works out of the box.

Linux

flutter_secure_storage setup for linux

Source

also see these issues: flutter_secure_storage#545

You need libsecret-1-dev and libjsoncpp-dev on your machine to build the project, and libsecret-1-0 and libjsoncpp1 to run the application (add it as a dependency after packaging your app). If you using snapcraft to build the project use the following:

parts:
  uet-lms:
    source: .
    plugin: flutter
    flutter-target: lib/main.dart
    build-packages:
      - libsecret-1-dev
      - libjsoncpp-dev
    stage-packages:
      - libsecret-1-0
      - libjsoncpp-dev
Apart from libsecret you also need a keyring service, for that you need either gnome-keyring (for Gnome users) or ksecretsservice (for KDE users) or other light provider like secret-service.

Notes

  • by default, due to its many configuration points, if the plugin fails to read/write using flutter_secure_storage, it will fall back to shared_preferences, which is NOT secure.