Credentials Provider
CredentialsProvider handles any username/password or form-based authentication flow. It delegates credential validation to a callback you supply — you own the logic and connect it to any backend.
Package: authyra (pure Dart, no Flutter dependency)
Two constructors
Basic — user profile only
Use when your backend manages sessions server-side (cookies, opaque tokens) and only returns the user profile on login:
CredentialsProvider(
id: 'email',
authorize: (creds) async {
final res = await myApi.post('/auth/login', body: creds);
if (res.statusCode != 200) return null; // wrong credentials
return AuthUser(
id: res.data['id'],
email: res.data['email'],
name: res.data['name'],
);
},
)
The authorize callback receives the params map passed to Authyra.instance.signIn() and returns an AuthUser or null. Returning null causes signIn to throw AuthenticationFailedException.
With tokens — JWT backend
Use when your backend returns access and refresh tokens in the sign-in response. Authyra stores them in the session and can refresh them silently:
CredentialsProvider.withTokens(
id: 'email',
authorize: (creds) async {
final res = await myApi.post('/auth/login', body: creds);
if (res.statusCode != 200) return null;
return AuthSignInResult(
user: AuthUser(
id: res.data['userId'],
email: res.data['email'],
name: res.data['name'],
),
accessToken: res.data['accessToken'],
refreshToken: res.data['refreshToken'],
expiresAt: DateTime.parse(res.data['expiresAt']),
);
},
)
.withTokens when your backend returns JWTs. It stores accessToken, refreshToken, and expiresAt in the session — enabling getAccessToken(), token refresh, and expiry tracking.Registration
Pass the provider to AuthyraClient:
final client = AuthyraClient(
providers: [
CredentialsProvider.withTokens(
id: 'email',
authorize: myAuthorize,
),
],
storage: SecureAuthStorage(), // or InMemoryStorage() for tests
);
The id must be unique within a client. Use it as the first argument to signIn:
await Authyra.instance.signIn('email', params: {
'email': 'alice@example.com',
'password': 's3cr3t',
});
Signing in
try {
final user = await Authyra.instance.signIn('email', params: {
'email': 'alice@example.com',
'password': 's3cr3t',
});
print('Welcome, ${user.name}');
} on AuthenticationFailedException {
// Provider returned null — wrong credentials
showError('Invalid email or password');
} on ProviderNotFoundException {
// No provider registered with id 'email'
showError('Auth not configured');
}
Multiple credential providers
Register as many CredentialsProvider instances as you need, each with a unique id:
AuthyraClient(
providers: [
CredentialsProvider(id: 'email', authorize: emailAuthorize),
CredentialsProvider(id: 'username', authorize: usernameAuthorize),
CredentialsProvider(id: 'phone', authorize: phoneAuthorize),
],
storage: storage,
)
Token refresh
CredentialsProvider sets supportsRefresh: false by default — it has no built-in refresh implementation.
To add refresh support, implement AuthProvider directly instead of using CredentialsProvider:
class MyApiProvider implements AuthProvider {
@override String get id => 'my-api';
@override AuthProviderType get type => AuthProviderType.credentials;
@override bool get supportsRefresh => true;
@override
Future<AuthSignInResult?> signIn({Map<String, dynamic>? params}) async {
final res = await myApi.post('/auth/login', body: params);
if (res.statusCode != 200) return null;
return AuthSignInResult(
user: AuthUser(id: res.data['id'], email: res.data['email']),
accessToken: res.data['accessToken'],
refreshToken: res.data['refreshToken'],
expiresAt: DateTime.parse(res.data['expiresAt']),
);
}
@override
Future<AuthTokenResult?> refreshToken(String refreshToken) async {
final res = await myApi.post('/auth/refresh',
body: {'refreshToken': refreshToken});
if (res.statusCode != 200) return null;
return AuthTokenResult(
accessToken: res.data['accessToken'],
expiresAt: DateTime.parse(res.data['expiresAt']),
);
}
}
Testing
Use InMemoryStorage and a simple authorize callback to test without a real backend:
import 'package:test/test.dart';
import 'package:authyra/authyra.dart';
void main() {
late AuthyraClient client;
setUp(() async {
client = AuthyraClient(
providers: [
CredentialsProvider(
id: 'email',
authorize: (creds) async {
if (creds?['password'] == 'correct') {
return AuthUser(id: '1', email: creds!['email'] as String);
}
return null; // wrong password
},
),
],
storage: InMemoryStorage(),
);
await client.initialize();
});
test('returns user on valid credentials', () async {
final user = await client.signIn('email', params: {
'email': 'alice@example.com',
'password': 'correct',
});
expect(user.email, 'alice@example.com');
});
test('throws on wrong password', () {
expect(
() => client.signIn('email', params: {
'email': 'alice@example.com',
'password': 'wrong',
}),
throwsA(isA<AuthenticationFailedException>()),
);
});
}
See also
- Email Auth guide → — full end-to-end walkthrough
- Custom Provider → — implement
AuthProviderdirectly - API Reference — AuthyraClient →