AuthCentral Flutter SDK — Integration Reference
A compact reference for integrating the AuthCentral SDK
(authcentral_sdk) into a host Flutter application. Every code block is
copy-pasteable. Prefer the snippets here over inventing APIs — every public
symbol shown below is part of the current SDK surface.
0. Use this page with an LLM assistant
This reference is also published as a Claude Skill file — a single Markdown document your AI assistant (Claude Code, Claude Desktop, Cursor, etc.) can load as context while integrating the SDK. Pointing the assistant at it is usually the fastest way to get correct, SDK-aware code generation.
Download: authcentral-sdk.md
(right-click → Save As, or curl below).
Install as a Claude Code skill
# Project-level (available only inside this repo)
mkdir -p .claude/skills/authcentral-sdk
curl -L <DOCS_URL>/skills/authcentral-sdk.md \
-o .claude/skills/authcentral-sdk/SKILL.md
# User-level (available in every project on your machine)
mkdir -p ~/.claude/skills/authcentral-sdk
curl -L <DOCS_URL>/skills/authcentral-sdk.md \
-o ~/.claude/skills/authcentral-sdk/SKILL.md
Claude Code picks up the skill on next launch; trigger it by asking "integrate AuthCentral SDK …".
Use with other LLM tools
- Cursor / Windsurf / generic chat UIs: download the file and attach it
to the conversation (drag-and-drop or
@filereference). - Raw prompt context: paste the file contents into your system prompt.
The file's own front-matter
descriptionfield tells the LLM when to use it, so most agentic tools will pick it up automatically once indexed.
The downloadable file carries Claude skill frontmatter (name /
description) so agentic tools pick it up automatically; the sections below
are the source of truth.
1. What the SDK does
- Provides a drop-in authentication screen (
SsoSdk.authScreen()) with full internal routing: login, signup, email/phone verification, backup, success. - Exposes a reactive token store (
SsoSdk.instance.tokenStore) and auth controller (SsoSdk.instance.authController) for headless use. - Supports email/password, Google, Apple, X (Twitter), Telegram and ETH/SOL/TON wallets.
- Ships three built-in themes (Chatoshi, VIP, Hero) in dark + light variants; fully custom themes are supported.
- 17 languages with auto-detection from device locale and per-string overrides.
Distribution: GitLab git dependency. Platforms: iOS 14+, Android API 23+. Requires: Flutter ≥ 3.41.0, Dart ≥ 3.11.0.
2. Golden-path quick start
Minimal working integration — copy, replace the three placeholders, ship.
# pubspec.yaml
dependencies:
authcentral_sdk:
git:
url: <gitlab-repo-url>
path: authCentralSDK
// lib/main.dart
import 'package:authcentral_sdk/authcentral_sdk.dart';
import 'package:flutter/material.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await SsoSdk.initialize(SsoConfig(
baseUrl: 'https://api.authcentral-1.hero-dev.xyz',
origin: SsoOrigin.heroDev,
appName: 'MyApp',
theme: SsoResolvedTheme.heroDark(),
));
runApp(const MyApp());
}
// Somewhere in your UI:
Future<void> openAuth(BuildContext context) async {
const appToken = String.fromEnvironment('APP_TOKEN');
final authToken = await SsoSdk.instance.getAccessToken(appToken);
await Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => SsoSdk.authScreen(
enabledProviders: const [
SsoProvider.emailPassword,
SsoProvider.google,
SsoProvider.apple,
],
authToken: authToken,
onSuccess: (tokens) => Navigator.of(context).pop(),
onCancel: () => Navigator.of(context).pop(),
),
),
);
}
// Reactive read:
StreamBuilder<SsoTokens?>(
stream: SsoSdk.instance.tokenStore.tokensStream,
initialData: SsoSdk.instance.tokenStore.currentTokens,
builder: (ctx, snap) => snap.data != null ? HomePage() : LoginPage(),
);
Two-token model. appToken (app-private) is passed to
getAccessToken() to mint an authToken. The authToken is passed to
authScreen(). After successful auth, SsoTokens (authToken + refreshToken)
are stored in SsoSdk.instance.tokenStore and streamed to you.
3. Installation
3.1 Dependency
dependencies:
authcentral_sdk:
git:
url: <gitlab-repo-url>
path: authCentralSDK
Run: flutter pub get.
3.2 iOS (ios/Runner/Info.plist)
Google Sign-In — add the reversed client ID:
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>com.googleusercontent.apps.YOUR_CLIENT_ID</string>
</array>
</dict>
</array>
Deep links (wallets, X) — add your app scheme to the same CFBundleURLTypes
array (alongside Google, not instead):
<dict>
<key>CFBundleURLSchemes</key>
<array><string>heroapp</string></array>
</dict>
3.3 Android (android/app/src/main/AndroidManifest.xml)
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="heroapp" />
</intent-filter>
For Google Sign-In on Android also drop google-services.json into
android/app/.
3.4 App secrets
Keep APP_TOKEN out of source. Use --dart-define-from-file=.env and
String.fromEnvironment('APP_TOKEN').
4. Initialization — SsoConfig
SsoSdk.initialize() must be called once before any other SDK call.
await SsoSdk.initialize(SsoConfig(
// Required
baseUrl: 'https://api.authcentral-1.hero-dev.xyz',
origin: SsoOrigin.heroDev,
appName: 'MyApp',
// Branding
logo: 'assets/icons/my_logo.svg', // asset path or https:// URL
// Theme (default: SsoResolvedTheme.chatoshiDark())
theme: SsoResolvedTheme.heroDark(),
// Localization (default: auto-detect from device)
locale: const Locale('en'),
textOverrides: {'login_title': 'Welcome back!'},
// Deep links for wallets / X / Telegram
appScheme: 'heroapp',
// Wallet provider configuration (required if SsoProvider.wallet is used)
walletConfig: const SsoWalletConfig(
walletConnectProjectId: 'your-project-id',
tonConnectManifestUrl: 'https://example.com/tonconnect-manifest.json',
),
// Analytics
analytics: SsoAnalyticsConfig(
onEvent: (event) => FirebaseAnalytics.instance
.logEvent(name: event.name, parameters: event.properties),
onError: (error) => Sentry.captureException(error),
suppressedEvents: {'sso_screen_viewed'},
),
// Global callbacks (fire on every successful auth, across screens)
onAuthSuccess: (tokens) => print('Authenticated'),
onAuthFailure: () => print('Auth failed'),
// Environment / networking / security
environment: SsoEnvironment.production,
debug: false,
connectTimeout: const Duration(seconds: 30),
receiveTimeout: const Duration(seconds: 30),
allowInsecureDevices: false,
));
4.1 Parameter reference
| Parameter | Type | Required | Default | Notes |
|---|---|---|---|---|
baseUrl | String | yes | — | AuthCentral backend URL |
origin | SsoOrigin | yes | — | Sent as Origin header (see below) |
appName | String | yes | — | Shown in auth screens |
logo | String? | no | null | Asset path or URL |
theme | SsoResolvedTheme? | no | chatoshiDark | See §8 |
locale | Locale? | no | null → auto | See §9 |
textOverrides | Map<String,String>? | no | null | Per-key string overrides |
appScheme | String? | no | null | Deep-link scheme (wallets, X) |
walletConfig | SsoWalletConfig? | no | null | Required for wallets |
analytics | SsoAnalyticsConfig? | no | null | Event + error forwarding |
onAuthSuccess | Function(SsoTokens)? | no | null | Global success hook |
onAuthFailure | Function()? | no | null | Global failure hook |
environment | SsoEnvironment | no | production | |
debug | bool | no | false | Verbose logs |
connectTimeout | Duration | no | 30s | |
receiveTimeout | Duration | no | 30s | |
allowInsecureDevices | bool | no | false | Rooted/jailbroken |
tokenStorageAdapter | TokenStorageAdapter? | no | null | Override secure storage |
httpInterceptors | List<dynamic>? | no | null | Extra Dio interceptors |
4.2 SsoOrigin values
| Enum | URL | Use for |
|---|---|---|
SsoOrigin.heroProd | https://auth.hero.io | Hero production |
SsoOrigin.heroDev | https://authcentral-1.hero-dev.xyz | Hero dev |
SsoOrigin.chatoshiProd | https://auth.chatoshi.ai | Chatoshi production |
SsoOrigin.chatoshiDev | https://auth.chatoshi.dev | Chatoshi dev |
SsoOrigin.vipProd | https://auth.vip.ai | VIP production |
SsoOrigin.vipDev | https://authcentral-1.dev-vip.net | VIP dev |
4.3 Teardown
SsoSdk.dispose(); // releases all SDK resources; re-init to use again
5. Opening the auth screen
Two presentation modes — same parameters (plus sheet-specific ones).
5.1 Full-page (Navigator.push)
Navigator.of(context).push(MaterialPageRoute(
builder: (_) => SsoSdk.authScreen(
enabledProviders: const [
SsoProvider.emailPassword,
SsoProvider.google,
SsoProvider.apple,
SsoProvider.telegram,
SsoProvider.x,
SsoProvider.wallet,
],
enabledWallets: const [
SsoWalletType.metaMask,
SsoWalletType.trustWallet,
SsoWalletType.walletConnect,
SsoWalletType.phantom,
SsoWalletType.tonKeeper,
],
authToken: authToken,
theme: SsoResolvedTheme.heroDark(), // overrides init-level theme
locale: 'en', // overrides init-level locale
onSuccess: (tokens) => Navigator.of(context).pop(),
onError: (err) => debugPrint('code=${err.code} msg=${err.message}'),
onCancel: () => Navigator.of(context).pop(),
termsUrl: 'https://example.com/terms',
privacyUrl: 'https://example.com/privacy',
),
));
5.2 Bottom sheet
await SsoSdk.showAuthBottomSheet(
context: context,
enabledProviders: const [SsoProvider.emailPassword, SsoProvider.google],
authToken: authToken,
onSuccess: (tokens) {/* sheet auto-dismisses */},
onCancel: () {/* swipe / scrim tap */},
// Sheet-specific:
heightFactor: 0.9, // fraction of screen height
topRadius: 20.0, // logical pixels
isDismissible: true, // tap scrim dismisses
enableDrag: true, // swipe down dismisses
);
When to use each.
- Push route: app has its own back stack and users expect a dedicated page.
- Bottom sheet: quick sign-in flow, e.g. gating a single action inside an existing screen.
5.3 Parameters (both modes)
| Parameter | Type | Required | Description |
|---|---|---|---|
enabledProviders | List<SsoProvider> | yes | Auth methods to show |
enabledWallets | List<SsoWalletType>? | no | Wallets; requires SsoProvider.wallet |
authToken | String? | no | Access token from getAccessToken() |
theme | SsoResolvedTheme? | no | Per-screen theme override |
locale | String? | no | Per-screen language ('en', 'ru', …) |
onSuccess | Function(SsoTokens)? | no | Called on success |
onCancel | VoidCallback? | no | Called on user dismiss |
onError | Function(SsoError)? | no | Called on critical errors |
termsUrl | String? | no | Terms of Service URL |
privacyUrl | String? | no | Privacy Policy URL |
Internal flow is managed by the SDK:
OAuth landing → Login | Sign Up
↓
Email / Phone verification
↓
Backup contact
↓
Success → onSuccess
Do not wrap authScreen() in another Navigator — it owns its own.
6. Providers
Each provider is opted-in via enabledProviders. Some require platform or
backend setup on top of the base install.
| Provider | Enum | Extra setup |
|---|---|---|
| Email / password | SsoProvider.emailPassword | None |
SsoProvider.google | iOS reversed-client-id URL scheme; Android google-services.json | |
| Apple | SsoProvider.apple | Backend: /apple/connect response must include a nonce field |
| X (Twitter) | SsoProvider.x | appScheme; backend must accept redirect_uri on /x/connect and whitelist the deep link |
| Telegram | SsoProvider.telegram | appScheme; verify backend does not validate origin |
| Wallet | SsoProvider.wallet | appScheme + walletConfig; see §6.1 |
6.1 Wallets
Pass walletConfig at init and enable at least one SsoWalletType:
await SsoSdk.initialize(SsoConfig(
baseUrl: '...', origin: SsoOrigin.heroDev, appName: 'MyApp',
appScheme: 'myapp',
walletConfig: const SsoWalletConfig(
walletConnectProjectId: 'your-project-id',
tonConnectManifestUrl: 'https://example.com/tonconnect-manifest.json',
),
));
SsoSdk.authScreen(
enabledProviders: const [SsoProvider.wallet],
enabledWallets: const [
SsoWalletType.metaMask,
SsoWalletType.trustWallet,
SsoWalletType.walletConnect,
SsoWalletType.phantom,
SsoWalletType.tonKeeper,
],
authToken: authToken,
);
| Wallet | Enum | Chain | Protocol |
|---|---|---|---|
| MetaMask | SsoWalletType.metaMask | ETH | WalletConnect v2 / deep link |
| Trust Wallet | SsoWalletType.trustWallet | ETH | WalletConnect v2 / deep link |
| WalletConnect | SsoWalletType.walletConnect | ETH (universal) | WalletConnect v2 |
| Phantom | SsoWalletType.phantom | SOL | Deep link + X25519 |
| Tonkeeper | SsoWalletType.tonKeeper | TON | TON Connect v2 (SSE bridge) |
7. Post-auth API — tokens, state, helpers
Everything useful lives under SsoSdk.instance.
7.1 Token store (SsoSdk.instance.tokenStore)
final store = SsoSdk.instance.tokenStore;
store.currentTokens; // SsoTokens? (snapshot)
store.authToken; // String?
store.refreshToken; // String?
store.isAuthenticated; // bool
store.tokensStream.listen((tokens) {
if (tokens == null) {/* logged out */}
});
Tokens are persisted in flutter_secure_storage — never in SharedPreferences,
SQLite or files. Never log them.
7.2 Auth controller (SsoSdk.instance.authController)
final c = SsoSdk.instance.authController;
c.stateStream.listen((state) {
switch (state) {
case SsoAuthenticated(): // signed in
case SsoUnauthenticated(): // signed out
case SsoAuthenticating(): // in progress
case SsoTokenRefreshing(): // silent refresh
case SsoAuthError(:final error): // failed
}
});
// Manual refresh (usually unnecessary — SDK refreshes at 80% TTL)
final res = await c.refreshToken();
switch (res) {
case SsoSuccess(): // ok
case SsoFailure(:final error): // handle
}
await c.logout(); // clears tokens + session state
7.3 Helpers
// Mint an access token for the auth flow
final authToken = await SsoSdk.instance.getAccessToken('app-private-token');
// Metadata about the OAuth-initiating side app
final info = await SsoSdk.instance.getSideApplicationInfo(authToken: authToken);
// info.allowProviders, info.accessToken.payload.redirectUrlOnSuccess
// Supported countries
final publicList = await SsoSdk.instance.getCountries(authToken: authToken);
final privateList = await SsoSdk.instance.getCountriesPrivate();
8. Theming
8.1 Built-in themes
SsoResolvedTheme.chatoshiDark(); SsoResolvedTheme.chatoshiLight();
SsoResolvedTheme.vipDark(); SsoResolvedTheme.vipLight();
SsoResolvedTheme.heroDark(); SsoResolvedTheme.heroLight();
Each overrides the button/input radius; the rest of the fields are colors:
| Theme | radiusButton | radiusInput |
|---|---|---|
| Chatoshi | 10.0 | 10.0 |
| VIP | 8.0 | 8.0 |
| Hero | 100.0 (pill) | 14.0 |
Set at init (default) or override per screen:
SsoSdk.initialize(SsoConfig(theme: SsoResolvedTheme.heroDark(), ...));
SsoSdk.authScreen(theme: SsoResolvedTheme.chatoshiLight(), ...);
8.2 Shape (radius) tokens
| Token | Default | Applied to |
|---|---|---|
radiusButton | 8.0 | Primary/secondary/provider buttons |
radiusInput | 8.0 | Text inputs, dropdowns |
radiusBlock | 24.0 | Cards, info blocks |
radiusButtonIcon | 1000.0 | Round icon buttons (keep large for pill) |
radiusBottomSheet | 8.0 | Auth bottom-sheet top corners |
Defaults above apply when you build a custom SsoResolvedTheme(...); built-in
themes set their own.
8.3 Fully custom theme
final myTheme = SsoResolvedTheme(
isDark: true,
fontFamily: 'Roboto',
// Shape tokens — any subset
radiusButton: 12.0,
radiusInput: 12.0,
radiusBlock: 24.0,
radiusButtonIcon: 1000.0,
radiusBottomSheet: 16.0,
text: SsoTextColors(
primary: Color(0xFFFFFFFF),
secondary: Color(0xFFB0B0B0),
tertiary: Color(0xFF808080),
disabled: Color(0xFF555555),
onGradient: Color(0xFFFFFFFF),
onSnackbarHint: Color(0xFFCCCCCC),
highlight: Color(0xFFFFD700),
inverse: SsoInverseTextColors(
primary: Color(0xFF000000),
secondary: Color(0xFF333333),
tertiary: Color(0xFF666666),
),
),
brand: SsoBrandColors(
primary: Color(0xFF6C5CE7),
onPrimary: Color(0xFFFFFFFF),
inverse: SsoInverseBrandColors(
primary: Color(0xFF6C5CE7),
onPrimary: Color(0xFFFFFFFF),
),
),
// ... all other color groups are required — see SsoResolvedTheme constructor
);
Color groups (all required in the constructor): text, brand, surface,
background, border, interactive, alerts, accent, disabled,
elevation, tag, gradient, graphs, skeleton, native, skrim,
links, logo, temporaryChat, gradients, shadow.
8.4 Extending a built-in theme
Copy every field from the base theme, then override what you need. Easy to forget the radius fields — if omitted they fall back to constructor defaults and you lose the base theme's shape:
final base = SsoResolvedTheme.heroDark();
final myTheme = SsoResolvedTheme(
text: base.text, surface: base.surface,
background: base.background, border: base.border,
interactive: base.interactive, alerts: base.alerts,
accent: base.accent, disabled: base.disabled,
elevation: base.elevation, tag: base.tag,
gradient: base.gradient, graphs: base.graphs,
skeleton: base.skeleton, native: base.native,
skrim: base.skrim, links: base.links,
logo: base.logo, temporaryChat: base.temporaryChat,
gradients: base.gradients, shadow: base.shadow,
isDark: base.isDark, fontFamily: base.fontFamily,
// Carry over shape tokens — otherwise pills become 8.0 rounded corners
radiusButton: base.radiusButton,
radiusInput: base.radiusInput,
radiusBlock: base.radiusBlock,
radiusButtonIcon: base.radiusButtonIcon,
radiusBottomSheet: base.radiusBottomSheet,
// Only what you're actually changing:
brand: SsoBrandColors(
primary: const Color(0xFFFF6B6B),
onPrimary: const Color(0xFFFFFFFF),
inverse: const SsoInverseBrandColors(
primary: Color(0xFFFF6B6B), onPrimary: Color(0xFFFFFFFF),
),
),
);
8.5 Reading theme inside custom widgets
final theme = SsoThemeProvider.of(context);
// theme.brand.primary, theme.text.secondary, theme.radiusButton, ...
9. Localization
17 languages: en, ru, de, fr, es, it, pt, pl, tr, ar, zh, ja, ko, hi, id, ms, fil. Unsupported locales fall back to en.
Priority (highest wins): authScreen(locale:) → SsoConfig(locale:) →
device locale → English.
// Global
SsoConfig(locale: const Locale('ru'), ...);
// Per screen
SsoSdk.authScreen(locale: 'fr', ...);
Per-string overrides apply across all languages:
SsoConfig(textOverrides: {
'login_title': 'Welcome back!',
'oauth_welcome_title': 'Sign in to {appName}',
});
String keys live in SsoStringKeys.
10. Common recipes
Gate a screen on auth state
StreamBuilder<SsoTokens?>(
stream: SsoSdk.instance.tokenStore.tokensStream,
initialData: SsoSdk.instance.tokenStore.currentTokens,
builder: (ctx, snap) => snap.data != null ? const HomePage() : const SignInPage(),
);
Attach the SDK's auth token to your own API calls
final token = SsoSdk.instance.tokenStore.authToken;
if (token != null) {
dio.options.headers['Authorization'] = 'Bearer $token';
}
// Or subscribe to tokensStream and refresh the header reactively.
Log user out
await SsoSdk.instance.authController.logout();
Forward SDK analytics to Firebase
SsoConfig(
analytics: SsoAnalyticsConfig(
onEvent: (e) => FirebaseAnalytics.instance.logEvent(
name: e.name, parameters: e.properties,
),
onError: (err) => Sentry.captureException(err),
),
);
11. Gotchas
- Call
initialize()once beforerunApp(). Everything else assumes the singleton exists. - Wallet provider requires
appScheme+walletConfig. Without the scheme, deep-link callbacks silently fail. - Apple provider needs backend cooperation.
/apple/connectresponse must include anoncefield; otherwise auth fails at verification. - X provider needs backend cooperation.
/x/connectmust accept aredirect_uriparameter and whitelist the deep-link callback URL. - Don't store tokens yourself — the SDK already persists them in
flutter_secure_storage. Reading viatokenStoreis the canonical path. - Never log
authToken/refreshToken. Use the state stream, notprint(), when debugging. - Extending a built-in theme: copy the radius fields. Omitted radii fall back to constructor defaults (8 / 8 / 24 / 1000 / 8), which silently breaks pill buttons / custom shape.
- The auth screen owns its own Navigator. Don't push nested routes inside
it; close it via
onSuccess/onCancel. getAccessToken(appToken)is required before opening the auth screen in the standard integration. The returnedauthTokenis what you pass toauthScreen(authToken:).- Dispose on teardown. Call
SsoSdk.dispose()if you ever need to re-initialize with different config (e.g. tests, multi-tenant apps).