createSession method
Implementation
Future<AuthUserSessionDto> createSession(CreateSessionRequest request) async {
_ensureInitialised();
if (_useMockData) {
await Future.delayed(const Duration(milliseconds: 500));
// Return a mock session specifically for the requested user
return AuthUserSessionDto.fromJson(_generateMockSession(request.userId));
}
try {
final client = await _createClientWithAuthHeaders();
final response = await client.post(
url: '$_sessionServiceUrl/userSession/api/session/createUserSession',
requestData: request.toJson(),
user: _user,
);
final statusCode = response?.statusCode;
// Handle PIN-related responses
if (statusCode == 428) {
logger.info(this, 'PIN required for user ${request.userId}');
throw PinRequiredException(cause: response?.data);
}
if (statusCode == 403) {
final data = response?.data;
final error = _extractStringField(data, 'error') ?? 'pin_invalid';
final locked = _extractBoolField(data, 'locked') ?? false;
final remainingAttempts = _extractIntField(data, 'remainingAttempts');
logger.warning(
this,
'PIN verification failed for user ${request.userId}: '
'$error (locked: $locked, remaining: $remainingAttempts)',
);
throw PinVerificationException(
error: error,
locked: locked,
remainingAttempts: remainingAttempts,
cause: data,
);
}
if (statusCode == 200 && response?.data != null) {
return AuthUserSessionDto.fromJson(response!.data['sessionResult']);
}
// Parse structured error from backend
final data = response?.data;
final errorCode = _extractStringField(data, 'error');
final errorMessage = _extractStringField(data, 'message');
throw AuthException(
_mapErrorCode(errorCode),
cause: errorMessage ?? data,
);
} on PinRequiredException {
rethrow;
} on PinVerificationException {
rethrow;
} on AuthException {
rethrow;
} catch (e, s) {
// Check if a DioException carries a PIN-related status code
if (e is DioException && e.response != null) {
final statusCode = e.response!.statusCode;
final data = e.response!.data;
if (statusCode == 428) {
throw PinRequiredException(cause: data);
}
if (statusCode == 403) {
final error = _extractStringField(data, 'error');
if (error == null || error == 'pin_invalid') {
final locked = _extractBoolField(data, 'locked') ?? false;
final remainingAttempts =
_extractIntField(data, 'remainingAttempts');
throw PinVerificationException(
error: error ?? 'pin_invalid',
locked: locked,
remainingAttempts: remainingAttempts,
cause: data,
);
}
// Non-PIN 403 — map via structured error code (e.g. user_not_authorized)
final errorMessage = _extractStringField(data, 'message');
throw AuthException(
_mapErrorCode(error),
cause: errorMessage ?? data,
);
}
// Any other response with a structured error body — map it
final errorCode = _extractStringField(data, 'error');
if (errorCode != null) {
final errorMessage = _extractStringField(data, 'message');
throw AuthException(
_mapErrorCode(errorCode),
cause: errorMessage ?? data,
);
}
}
logger.error(
this,
'Exception while creating session',
error: e,
stackTrace: s,
);
rethrow;
}
}