authwebview 2.1.0 copy "authwebview: ^2.1.0" to clipboard
authwebview: ^2.1.0 copied to clipboard

A Flutter package for OAuth authentication using WebView. Originally developed for Rapider.ai (https://www.rapider.ai). Supports PKCE, multiple providers, and secure token storage.

example/lib/main.dart

import 'package:authwebview/authwebview.dart';
import 'package:flutter/material.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'dart:convert';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'AuthWebView Example',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue),
        useMaterial3: true,
      ),
      home: const HomePage(),
    );
  }
}

class HomePage extends StatefulWidget {
  const HomePage({super.key});

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  AuthorizationTokenResponse? _tokenResponse;
  bool _isLoading = true;
  final storage = const FlutterSecureStorage();

  final List<OAuthProvider> _providers = [
    // Example Google provider
    const OAuthProvider(
      name: 'Google',
      discoveryUrl:
          'https://accounts.google.com/.well-known/openid-configuration',
      clientId: 'your-client-id',
      redirectUrl: 'com.example.app:/oauth2callback',
      scopes: ['openid', 'profile', 'email'],
    ),
    // Example Microsoft provider
    const OAuthProvider(
      name: 'Microsoft',
      discoveryUrl:
          'https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration',
      clientId: 'your-client-id',
      redirectUrl: 'com.example.app:/oauth2callback',
      scopes: ['openid', 'profile', 'email', 'offline_access'],
    ),
  ];

  @override
  void initState() {
    super.initState();
    _clearTokens();
    _loadSavedTokens();
  }

  Future<void> _loadSavedTokens() async {
    try {
      final tokenJson = await storage.read(key: 'oauth_tokens');
      if (tokenJson != null) {
        setState(() {
          _tokenResponse = AuthorizationTokenResponse.fromJson(
            json.decode(tokenJson),
          );
        });
      }
    } catch (e) {
      debugPrint('Error loading saved tokens: $e');
    } finally {
      setState(() {
        _isLoading = false;
      });
    }
  }

  Future<void> _saveTokens(AuthorizationTokenResponse tokens) async {
    try {
      await storage.write(
        key: 'oauth_tokens',
        value: json.encode(tokens.toJson()),
      );
    } catch (e) {
      debugPrint('Error saving tokens: $e');
    }
  }

  Future<void> _clearTokens() async {
    try {
      await storage.delete(key: 'oauth_tokens');
    } catch (e) {
      debugPrint('Error clearing tokens: $e');
    }
  }

  Future<void> _login(OAuthProvider provider) async {
    try {
      final result = await OAuthService.performOAuthFlow(
        context,
        provider,
        loadingWidget: const Center(child: CircularProgressIndicator()),
        backgroundColor: Theme.of(
          context,
        ).colorScheme.surface, // background -> surface
      );

      if (result != null) {
        setState(() {
          _tokenResponse = result;
        });
        await _saveTokens(result);
      }
    } catch (e) {
      if (mounted) {
        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(
            content: Text('Login failed: ${e.toString()}'),
            backgroundColor: Theme.of(context).colorScheme.error,
          ),
        );
      }
    }
  }

  Future<void> _logout(OAuthProvider provider) async {
    if (_tokenResponse?.idToken == null) {
      setState(() {
        _tokenResponse = null;
      });
      await _clearTokens();
      return;
    }

    try {
      final success = await OAuthService.logout(
        provider,
        _tokenResponse!.idToken!,
      );

      if (success) {
        setState(() {
          _tokenResponse = null;
        });
        await _clearTokens();
      } else {
        throw Exception('Logout failed');
      }
    } catch (e) {
      if (mounted) {
        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(
            content: Text('Logout failed: ${e.toString()}'),
            backgroundColor: Theme.of(context).colorScheme.error,
          ),
        );
      }
    }
  }

  @override
  Widget build(BuildContext context) {
    if (_isLoading) {
      return const Scaffold(body: Center(child: CircularProgressIndicator()));
    }

    return Scaffold(
      appBar: AppBar(
        title: const Text('AuthWebView Example'),
        backgroundColor: Theme.of(context).colorScheme.primaryContainer,
      ),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: SingleChildScrollView(
          child: Column(
            mainAxisSize: MainAxisSize.min,
            crossAxisAlignment: CrossAxisAlignment.stretch,
            children: [
              if (_tokenResponse == null) ...[
                const Text(
                  'Choose a provider to login:',
                  style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
                ),
                const SizedBox(height: 20),
                ..._providers.map(
                  (provider) => Padding(
                    padding: const EdgeInsets.only(bottom: 10),
                    child: ElevatedButton(
                      onPressed: () => _login(provider),
                      child: Text('Login with ${provider.name}'),
                    ),
                  ),
                ),
              ] else ...[
                Card(
                  child: Padding(
                    padding: const EdgeInsets.all(16.0),
                    child: Column(
                      crossAxisAlignment: CrossAxisAlignment.start,
                      children: [
                        const Text(
                          'Authentication Successful!',
                          style: TextStyle(
                            fontSize: 20,
                            fontWeight: FontWeight.bold,
                            color: Colors.green,
                          ),
                        ),
                        const SizedBox(height: 20),
                        Text('Access Token: ${_tokenResponse!.accessToken}'),
                        if (_tokenResponse!.refreshToken != null) ...[
                          const SizedBox(height: 10),
                          Text(
                            'Refresh Token: ${_tokenResponse!.refreshToken}',
                          ),
                        ],
                        if (_tokenResponse!.accessTokenExpirationDateTime !=
                            null) ...[
                          const SizedBox(height: 10),
                          Text(
                            'Expires: ${_tokenResponse!.accessTokenExpirationDateTime}',
                          ),
                        ],
                        const SizedBox(height: 20),
                        ElevatedButton(
                          onPressed: () => _logout(_providers.first),
                          style: ElevatedButton.styleFrom(
                            backgroundColor: Theme.of(
                              context,
                            ).colorScheme.error,
                            foregroundColor: Theme.of(
                              context,
                            ).colorScheme.onError,
                          ),
                          child: const Text('Logout'),
                        ),
                      ],
                    ),
                  ),
                ),
              ],
            ],
          ),
        ),
      ),
    );
  }
}
1
likes
125
points
152
downloads

Publisher

unverified uploader

Weekly Downloads

A Flutter package for OAuth authentication using WebView. Originally developed for Rapider.ai (https://www.rapider.ai). Supports PKCE, multiple providers, and secure token storage.

Repository (GitHub)
View/report issues

Documentation

API reference

License

MIT (license)

Dependencies

crypto, device_info_plus, flutter, flutter_inappwebview, http, package_info_plus

More

Packages that depend on authwebview