authenticate method
Authenticates a user and returns a User object.
This is the main authentication method that handles email/password authentication. It creates a new user if they don't exist (based on the policy) or signs in an existing user. The method integrates with device attestation for enhanced security.
Parameters
challengeToken: Optional challenge token (will be generated if not provided)email: The user's email address (required)emailVerified: Whether the email is already verifiedname: The user's display name (for new users)password: The user's password (required for email/password auth)tags: List of tags to assign to the user (for new users)policy: Authentication policy controlling user creation/sign-in behaviordoNotNotify: If true, suppresses sending welcome/notification emails
Returns
A Future that resolves to a User object representing the authenticated user
Throws
- Exception if password is not provided for email/password authentication
HttpExceptionif there's a network errorCalljmpExceptionif authentication fails or policy restrictions apply
Example
// Sign in existing user or create new user
final user = await calljmp.users.auth.email.authenticate(
email: 'user@example.com',
password: 'secure_password',
name: 'John Doe',
tags: ['role:member', 'plan:free'],
policy: UserAuthenticationPolicy.signInOrCreate,
);
print('Authenticated user: ${user.name} (${user.email})');
Implementation
Future<User> authenticate({
String? challengeToken,
required String email,
bool? emailVerified,
String? name,
String? password,
List<String>? tags,
UserAuthenticationPolicy? policy,
bool? doNotNotify,
}) async {
if (password == null) {
throw Exception("Password is required for email/password authentication");
}
if (challengeToken == null) {
final result = await _auth.challenge();
challengeToken = result.challengeToken;
}
final attestationHash = base64.encode(
sha256.convert(utf8.encode("$email:$challengeToken")).bytes,
);
final attest = await _attestation
.attest({"hash": attestationHash})
.catchError((error) {
developer.log(
"Failed to attest, this is fatal error unless it is in debug mode",
name: "calljmp",
error: error,
);
return Null;
});
final attestationToken = base64.encode(utf8.encode(jsonEncode(attest)));
final result = await http
.request("${_config.serviceUrl}/users/auth/email")
.use(http.context(_config))
.use(http.access())
.post({
"token": challengeToken,
"attestationToken": attestationToken,
"email": email,
"password": password,
if (emailVerified != null) "emailVerified": emailVerified,
if (name != null) "name": name,
if (tags != null) "tags": tags,
if (policy != null) "policy": policy.value,
"doNotNotify": doNotNotify ?? false,
})
.json(
(json) => (
accessToken: json["accessToken"],
user: User.fromJson(json["user"]),
),
);
await CalljmpStore.instance.put(
CalljmpStoreKey.accessToken,
result.accessToken,
);
return result.user;
}