Flutter SDK

The auth_gate_flutter package brings AuthGate authentication to Flutter apps. OAuth flows open the system browser and return via deep link, tokens are stored in secure storage, and session restore happens automatically on app launch.


Installation

Add to your pubspec.yaml:

dependencies:
  auth_gate_flutter: ^0.6.0

Or install via CLI:

flutter pub add auth_gate_flutter

Dependencies http, flutter_secure_storage, url_launcher, and app_links are included automatically.


The SDK uses deep links to receive OAuth callbacks. Configure your app's URL scheme for each platform.

Android

Add to android/app/src/main/AndroidManifest.xml inside the <activity> tag:

<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="myapp" android:host="auth" />
</intent-filter>

iOS

Add to ios/Runner/Info.plist:

<key>CFBundleURLTypes</key>
<array>
  <dict>
    <key>CFBundleURLSchemes</key>
    <array>
      <string>myapp</string>
    </array>
  </dict>
</array>

Then register the callback URL in the AuthGate dashboard:

myapp://auth/callback

Navigate to Dashboard → Callback URLs and add the URL above.


Setup

1. Wrap your app with AuthGateProvider

lib/main.dart

import 'package:auth_gate_flutter/auth_gate_flutter.dart';

void main() {
  runApp(
    AuthGateProvider(
      config: AuthGateConfig(
        apiKey: 'ag_...',
        baseUrl: 'https://www.authgate.dev',
        scheme: 'myapp',
      ),
      child: const MyApp(),
    ),
  );
}

2. Access auth state

lib/screens/profile.dart

import 'package:auth_gate_flutter/auth_gate_flutter.dart';

class ProfilePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final auth = AuthGateProvider.of(context);

    if (auth.isLoading) {
      return const Center(child: CircularProgressIndicator());
    }

    if (!auth.isAuthenticated) {
      return const LoginPage();
    }

    return Center(
      child: Column(
        children: [
          Text('Hello, ${auth.user!.name}'),
          ElevatedButton(
            onPressed: auth.logout,
            child: const Text('Sign out'),
          ),
        ],
      ),
    );
  }
}

Authentication

OAuth

Opens the system browser for the OAuth flow. The SDK handles the deep link callback and token storage automatically.

final auth = AuthGateProvider.of(context);

await auth.loginWithOAuth(OAuthProvider.google);
await auth.loginWithOAuth(OAuthProvider.github);
await auth.loginWithOAuth(OAuthProvider.discord);
await auth.loginWithOAuth(OAuthProvider.azure);
await auth.loginWithOAuth(OAuthProvider.apple);

Email

final auth = AuthGateProvider.of(context);

// Sign up (with optional locale)
await auth.client.emailSignup(
  email: 'alice@example.com',
  password: 'password123',
  name: 'Alice',
  locale: 'it', // Optional
);

// Sign in (with optional locale)
final response = await auth.loginWithEmail(
  'alice@example.com',
  'password123',
  locale: 'it', // Optional
);

if (response.mfaRequired) {
  // MFA challenge — prompt user for code
  await auth.verifyMfa(
    response.mfaChallenge!,
    totpCode,
    MfaMethod.totp,
  );
}

Magic link

await auth.client.magicLinkSend(
  email: 'alice@example.com',
  callbackUrl: 'myapp://auth/callback',
);
// User receives an email with a link that opens the app

SMS

// Send verification code
await auth.client.smsSendCode(phone: '+15551234567');

// Verify and sign in
await auth.loginWithSms('+15551234567', '123456');

Route protection

Use the AuthGate widget for conditional rendering based on auth state:

import 'package:auth_gate_flutter/auth_gate_flutter.dart';

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return AuthGate(
      authenticated: const DashboardScreen(),
      unauthenticated: const LoginScreen(),
      loading: const Center(child: CircularProgressIndicator()),
    );
  }
}
ParameterTypeDescription
authenticatedWidgetShown when user is signed in
unauthenticatedWidgetShown when user is not signed in
loadingWidget?Shown while session is restoring (defaults to empty)

Configuration

  • Name
    apiKey
    Type
    String
    Description

    Your AuthGate API key.

  • Name
    baseUrl
    Type
    String
    Description

    URL of your AuthGate instance.

  • Name
    scheme
    Type
    String
    Description

    Deep link scheme for OAuth callbacks (e.g. "myapp").

  • Name
    sessionMaxAge
    Type
    int
    Description

    Session lifetime in seconds (default: 7 days).

  • Name
    callbackPath
    Type
    String
    Description

    Deep link callback path fragment.


API reference

AuthGateProvider

Widget that provides AuthNotifier to the widget tree via InheritedNotifier.

final auth = AuthGateProvider.of(context);

AuthNotifier

Property / MethodTypeDescription
userAuthGateUser?Current user or null
isLoadingboolTrue while restoring session on launch
isAuthenticatedboolWhether a user is signed in
clientAuthGateClientLow-level HTTP client for advanced usage
loginWithOAuth(provider)Future<void>Start OAuth flow in system browser
loginWithEmail(email, password)Future<AuthResponse>Email sign-in (may return MFA challenge)
loginWithSms(phone, code)Future<void>Verify SMS code and sign in
verifyMfa(challenge, code, method)Future<void>Complete MFA challenge
logout()Future<void>Sign out and clear secure storage

AuthGateUser

class AuthGateUser {
  String id;        // Unique user ID
  String? email;    // Email (null for SMS-only users)
  String? phone;    // Phone in E.164 format
  String? name;     // Display name
  String? picture;  // Avatar URL
  String provider;  // Auth provider used
}

OAuthProvider

enum OAuthProvider { google, github, discord, azure, apple }

How sessions work

  • Tokens are stored in flutter_secure_storage (Keychain on iOS, EncryptedSharedPreferences on Android)
  • On app launch, the stored token is verified server-side
  • If the token is expired, the refresh token is used automatically
  • Token refresh is scheduled before expiry to maintain seamless sessions

Was this page helpful?