Ajolote

pub package pub points publisher License: MIT

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.