{"id":32281155,"url":"https://github.com/fluo-dev/flutter-sdk","last_synced_at":"2025-10-23T00:54:48.852Z","repository":{"id":257816384,"uuid":"855244037","full_name":"fluo-dev/flutter-sdk","owner":"fluo-dev","description":null,"archived":false,"fork":false,"pushed_at":"2025-10-16T06:37:57.000Z","size":6296,"stargazers_count":43,"open_issues_count":0,"forks_count":3,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-10-23T00:54:40.584Z","etag":null,"topics":["authentication","flutter","onboarding","registration","sdk","user-onboarding"],"latest_commit_sha":null,"homepage":"https://fluo.dev","language":"Dart","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/fluo-dev.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2024-09-10T14:59:45.000Z","updated_at":"2025-10-16T06:37:32.000Z","dependencies_parsed_at":null,"dependency_job_id":"e8738bde-4b00-4b2e-8198-1ac6f35fe5a6","html_url":"https://github.com/fluo-dev/flutter-sdk","commit_stats":null,"previous_names":["fluo-dev/flutter-sdk"],"tags_count":25,"template":false,"template_full_name":null,"purl":"pkg:github/fluo-dev/flutter-sdk","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fluo-dev%2Fflutter-sdk","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fluo-dev%2Fflutter-sdk/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fluo-dev%2Fflutter-sdk/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fluo-dev%2Fflutter-sdk/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fluo-dev","download_url":"https://codeload.github.com/fluo-dev/flutter-sdk/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fluo-dev%2Fflutter-sdk/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":280540650,"owners_count":26347724,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-22T02:00:06.515Z","response_time":63,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["authentication","flutter","onboarding","registration","sdk","user-onboarding"],"created_at":"2025-10-23T00:54:45.762Z","updated_at":"2025-10-23T00:54:48.841Z","avatar_url":"https://github.com/fluo-dev.png","language":"Dart","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Fluo\n\n\u003e **📝 Looking for the full documentation?\n\u003e [Check out the new Fluo SDK docs →](https://docs.page/fluo-dev/flutter-sdk)**\n\n- [Getting started](#getting-started)\n- [More about the SDK](#more-about-the-sdk)\n- [Integrating with Firebase](#integrating-with-firebase)\n- [Integrating with Supabase](#integrating-with-supabase)\n- [Integrating with any backend](#integrating-with-any-backend)\n- [Customizing the theme](#Customizing-the-theme)\n\n## Getting started\n\nAdd the package to your dependencies:\n\n```bash\nflutter pub add fluo\n```\n\nAdd the `FluoLocalizations.delegate` to your app's `localizationsDelegates`:\n\n```dart\nMaterialApp(\n  // ...other properties...\n  localizationsDelegates: const [\n    FluoLocalizations.delegate,\n    // ...other delegates...\n  ],\n)\n```\n\nUse the Fluo SDK:\n\n```dart\nimport 'package:fluo/fluo.dart';\nimport 'package:fluo/fluo_onboarding.dart';\n\nFutureBuilder(\n  // Get your api key from https://dashboard.fluo.dev (it's free)\n  future: Fluo.init('YOUR_API_KEY'),\n  builder: (context, snapshot) {\n    // Check if Fluo is initialized.\n    if (!Fluo.isInitialized) {\n      return const Scaffold();\n    }\n\n    // Fluo is initialized. Check if the user is ready.\n    if (!Fluo.instance.isUserReady()) {\n      return FluoOnboarding(\n        fluoTheme: FluoTheme.native(), // or FluoTheme.web()\n        onUserReady: () =\u003e setState(() {}), // force build\n      );\n    }\n\n    // User is ready!\n    // An example `ConnectedScreen` widget is available in\n    // the example/lib/main.dart file.\n    return ConnectedScreen(\n      onSignOut: () async {\n        await Fluo.instance.clearSession();\n        setState(() {});\n      },\n    );\n  },\n)\n```\n\n**For macOS**, make sure you have networking allowed by adding this key to both `{your-app}/macos/Runner/DebugProfile.entitlements` and `{your-app}/macos/Runner/Release.entitlements`:\n\n```xml\n\u003cdict\u003e\n\t\u003c!-- Add this key set to true --\u003e\n\t\u003ckey\u003ecom.apple.security.network.client\u003c/key\u003e\n\t\u003ctrue/\u003e\n\u003c/dict\u003e\n```\n\n## More about the SDK\n\nBelow are the most important methods to know:\n\n```dart\n// Initialize the SDK\nawait Fluo.init('YOUR_API_KEY');\n\n// Check if init is done\nif (Fluo.isInitialized) {\n  // ...\n}\n\n// Check if user is ready (valid session + complete user attributes)\nif (Fluo.instance.isUserReady()) {\n  // ...\n}\n\n// Only check if a session exists\nif (Fluo.instance.hasSession()) {\n  // ...\n}\n\n// Get a certified fresh access token. \"Certified fresh\" means that\n// if the access token has expired, Fluo will first refresh it before\n// returning it. This is an important method if you selected a \"custom\"\n// backend.\nString accessToken = await Fluo.instance.getAccessToken();\n\n// Force refresh the session. Generally, you should not need it because\n// `Fluo.instance.getAccessToken()` handles refreshing the session.\nawait Fluo.instance.refreshSession();\n\n// Clear the locally stored token. This is equivalent to a sign out.\nawait Fluo.instance.clearSession();\n\n// User data\nString userId = Fluo.instance.session.user.id; // \"jzi8w7bdou4m0kq\"\nString email = Fluo.instance.session.user.email; // \"peter.parker@marvel.com\"\nString mobileE164 = Fluo.instance.session.user.mobileE164; // \"+14155556766\"\nString mobileIso2 = Fluo.instance.session.user.mobileIso2; // \"US\"\nString firstName = Fluo.instance.session.user.firstName; // \"Peter\"\nString lastName = Fluo.instance.session.user.lastName; // \"Parker\"\n\n// If you build your own connect screen (and don't use FluoOnboarding)\n// When authentication is done, these flows will automatically show the\n// registration steps (you don't need to call `showRegisterFlow`).\nFluo.instance.showConnectWithEmailFlow(/* ... */)\nFluo.instance.showConnectWithMobileFlow(/* ... */)\nFluo.instance.showConnectWithGoogleFlow(/* ... */)\nFluo.instance.showConnectWithAppleFlow(/* ... */)\n\n// Force show the registration steps. Generally, you should not need it.\nFluo.instance.showRegisterFlow(/* ... */)\n```\n\n## Integrating with Firebase\n\nSelect 'Firebase' for your backend. Once complete, when users are onboarded, Fluo forwards their info to:\n\n1. the Firebase Authentication service\n2. a `users` table created automatically in the Firestore Database (make sure the Firestore Database is initialized)\n\nBack to your app code, to initialize correctly the Firebase session, use the `Fluo.instance.session.firebaseToken` as below:\n\n```dart\n// 1. Initialize the Firebase client somewhere in your code\n// 2. Make sure Fluo is initialized and has a session\n// 3. Use 'signInWithCustomToken' as shown below\nif (Fluo.isInitialized) {\n  final fluoSession = Fluo.instance.session;\n  if (fluoSession != null) {\n    final firebaseToken = fluoSession.firebaseToken!;\n    await FirebaseAuth.instance.signInWithCustomToken(firebaseToken);\n  }\n}\n```\n\n## Integrating with Supabase\n\nSelect 'Supabase' for your backend. Once complete, when users are onboarded, Fluo forwards their info to:\n\n1. the Supabase Authentication service\n2. a `users` table that you will create as part of the Supabase setup (no worries, it's a simple copy-paste)\n\nBack to your app code, to initialize correctly the Supabase session, use the `Fluo.instance.session.supabaseSession` as below:\n\n```dart\n// 1. Initialize the Supabase client somewhere in your code\n// 2. Make sure Fluo is initialized and has a session\n// 3. Use 'recoverSession' as shown below\nif (Fluo.isInitialized) {\n  final fluoSession = Fluo.instance.session;\n  if (fluoSession != null) {\n    final supabaseSession = fluoSession.supabaseSession!;\n    await Supabase.instance.client.auth.recoverSession(supabaseSession);\n  }\n}\n```\n\n## Integrating with any backend\n\nSelect 'Custom' for your backend. The general idea is to use the JWT access token provided by Fluo to get a unique user id via the `\"sub\"` JWT claim.\n\nHere is a full example to understand how it works:\n\n1. Wherever you need it, call `Fluo.instance.getAccessToken()` to get the JWT access token generated by Fluo and send it to your backend.\n\n```dart\nimport 'dart:convert';\nimport 'package:http/http.dart' as http;\n\n// Example of a function that gets a user. If the user\n// doesn't exist yet, it should create it first.\nFuture\u003cUser\u003e getOrCreateUser() async {\n  final accessToken = await Fluo.instance.getAccessToken();\n  final response = await http.post(\n    Uri.parse('https://your-backend.com/api/user/me'),\n    // Send the JWT access token to securely authenticate\n    // the user and retrieve the user id.\n    headers: {\n      'authorization': 'Bearer $accessToken',\n    },\n    // Send the user data to create or update the user if\n    // the object does not exist yet.\n    body: jsonEncode(Fluo.instance.session.user),\n  );\n  return User.fromJson(jsonDecode(response.body));\n}\n```\n\n2. In your backend, decode the access token to get the JWT payload.\n\n```js\nconst jwt = require(\"jsonwebtoken\")\n\n// This is your JWT secret key (do not share it with anyone)\n// You can find it on https://dashboard.fluo.dev/backend\nconst SECRET_KEY = \"YOUR_SECRET_KEY\"\n\n// Following on the example, here is the corresponding endpoint.\n// Note that this is simplified and does not handle all edge cases.\napp.post(\"/api/user/me\", async (req, res) =\u003e {\n  const accessToken = req.headers[\"authorization\"].split(\" \")[1]\n\n  // Decode the access token using your secret key\n  const payload = jwt.verify(accessToken, SECRET_KEY)\n\n  // 'payload.sub' contains a unique user id generated by Fluo\n  const userId = payload.sub\n\n  // Find the user by id\n  let user = await User.findOne({ id: userId }) // or { fluoId: userId }\n\n  // If the user doesn't exist, create it\n  if (!user) {\n    const { email, mobileE164, mobileIso2, firstName, lastName } = req.body\n    user = await User.create({\n      id: userId,\n      email: email,\n      mobileE164: mobileE164,\n      mobileIso2: mobileIso2,\n      firstName: firstName,\n      lastName: lastName,\n    })\n  }\n\n  return res.status(200).json(user)\n})\n```\n\n3. If you need to go further, here is a complete example of the payload. For example, for increased security, you might want to verify that the token has not expired.\n\n```js\n{\n  \"sub\": \"2rztxukf57pnjz9\", // user id\n  \"iat\": 1744039599, // issued at\n  \"exp\": 1744043199, // expires 1 hour after being issued\n  \"iss\": \"fluo.dev\", // issuer\n}\n```\n\n## Customizing the theme\n\nPass a `FluoTheme` to the `FluoOnboarding` component.\n\n**For iOS, Android, macOS**\n\n```dart\nFluoOnboarding(\n  // ...other properties...\n  fluoTheme: FluoTheme.native(/* parameters */),\n)\n```\n\n**For web**\n\n```dart\nFluoOnboarding(\n  // ...other properties...\n  fluoTheme: FluoTheme.web(/* parameters */),\n)\n```\n\n**Parameters**\n\n```dart\n{\n  Color? primaryColor,\n  Color? inversePrimaryColor,\n  Color? accentColor,\n  EdgeInsets? screenPadding,\n  ButtonStyle? connectButtonStyle,\n  ButtonStyle? connectButtonStyleGoogle,\n  ButtonStyle? connectButtonStyleApple,\n  TextStyle? connectButtonTextStyle,\n  TextStyle? connectButtonTextStyleGoogle,\n  TextStyle? connectButtonTextStyleApple,\n  double? connectButtonIconSize,\n  Widget? connectButtonIconEmail,\n  Widget? connectButtonIconMobile,\n  Widget? connectButtonIconGoogle,\n  Widget? connectButtonIconApple,\n  TextStyle? legalTextStyle,\n  EdgeInsets? legalTextPadding,\n  TextStyle? modalTitleTextStyle,\n  TextStyle? titleStyle,\n  InputDecorationTheme? inputDecorationTheme,\n  TextStyle? inputTextStyle,\n  TextStyle? inputErrorStyle,\n  TextAlignVertical? inputTextAlignVertical,\n  ButtonStyle? continueButtonStyle,\n  Size? continueButtonProgressIndicatorSize,\n  Color? continueButtonProgressIndicatorColor,\n  double? continueButtonProgressIndicatorStrokeWidth,\n  EdgeInsets? countryItemPadding,\n  Color? countryItemHighlightColor,\n  TextStyle? countryTextStyle,\n  PinTheme? codeInputThemeDefault,\n  PinTheme? codeInputThemeFocused,\n  PinTheme? codeInputThemeSubmitted,\n  PinTheme? codeInputThemeFollowing,\n  PinTheme? codeInputThemeDisabled,\n  PinTheme? codeInputThemeError,\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffluo-dev%2Fflutter-sdk","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffluo-dev%2Fflutter-sdk","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffluo-dev%2Fflutter-sdk/lists"}