Ajolote
Flutter client for Ajolote, an authentication server with multi-tenant isolation, JWT-based sessions, and built-in support for OTP, biometrics, and social login.
Why Ajolote?
Most auth SDKs assume one app, one tenant, and tightly couple your frontend to a specific vendor. Ajolote is built for organizations that:
- Run multiple apps that share users but isolate data per product
- Need OTP-by-SMS, social login, and biometric unlock without stitching three vendors together
- Want to own the auth server (it's open source) instead of paying per MAU
You run the server, this package talks to it.
Features
- π Email + password authentication
- π± SMS OTP via the Ajolote server
- π Social OAuth (Google) with deep links and CSRF state validation
- π Automatic access token refresh with concurrent-request deduplication
- π‘οΈ Secure token storage in Keychain/Keystore (via
flutter_secure_storage) - π Optional biometric unlock (via
local_auth) - π Reactive via
ChangeNotifierβ works with any state management - π Server-to-server client for Dart backends (Shelf, Dart Frog)
- π― Multi-tenant by design β each app is an isolated tenant
Installation
Add ajolote to your pubspec.yaml:
β```yaml dependencies: flutter: sdk: flutter ajolote: ^0.2.1
Optional, depending on which features you use:
local_auth: ^2.3.0 # for biometric unlock app_links: ^6.3.0 # for social OAuth url_launcher: ^6.3.0 # for social OAuth β```
Then run:
βbash flutter pub get β
Quickstart
β```dart import 'package:flutter/material.dart'; import 'package:ajolote/ajolote.dart';
void main() async { WidgetsFlutterBinding.ensureInitialized();
final auth = AjoloteClient( appId: 'my-app', baseUrl: Uri.parse('https://auth.example.com'), );
await auth.init(); // restores previous session if any
runApp(MyApp(auth: auth)); } β```
Sign in with email and password
β```dart await auth.signInWithEmail( email: 'user@example.com', password: 'secret', );
// auth.session now has the user and tokens final user = auth.session?.user; β```
Get a valid access token for your API calls
β```dart final token = await auth.getValidToken();
final response = await http.get( Uri.parse('https://your-api.example.com/resource'), headers: {'Authorization': 'Bearer $token'}, ); β```
The client automatically refreshes the access token when it's near expiration, deduplicating concurrent refresh requests.
Reactive UI with ChangeNotifier
βdart ListenableBuilder( listenable: auth, builder: (context, _) { if (auth.session == null) return const LoginScreen(); return HomeScreen(user: auth.session!.user); }, ) β
Works with Provider, Riverpod, BLoC, or any state management that supports Listenable.
Sign out
βdart await auth.signOut(); β
Advanced features
See the example app for complete implementations of:
- SMS OTP flow (
PhoneAuth) - Google OAuth with deep links (
SocialAuth) - Biometric unlock (
Biometric) - Server-to-server token validation (
AjoloteServerClient)
The Ajolote server
This package is a client. You need an Ajolote server running to use it. The server handles user storage, token issuance, OTP delivery, OAuth flows, and multi-tenant isolation.
Contributing
Issues and PRs are welcome at github.com/cuatro-quinas/ajolote.
License
MIT β see LICENSE.
Libraries
- ajolote
- Ajolote β Cliente Flutter para el servicio de autenticaciΓ³n centralizado de Anfibia/4Quinas.