ssoRequiredFrom function
Turns an "SSO required" rejection into a typed exception, or returns null.
The API keeps the machine code in message so existing branching keeps
working, and puts the account to use alongside it. HttpException.body
holds the raw response, which is the only place those extra fields live.
Both statuses count. The API answers 403 when a login, register or forgot-password is refused, and 401 when an already-signed-in session is ended because its domain has since been bound to an account - and that second case is the one an app most needs to recognise, because the user is mid-session and has to be sent to the SSO button rather than a login form. Matching only 403 made exactly that case look like an ordinary expiry.
Implementation
SsoRequiredException? ssoRequiredFrom(Object error) {
if (error is! HttpException) return null;
if (error.code != AuthErrors.ssoRequired) return null;
if (error.status != 401 && error.status != 403) return null;
Map<String, dynamic> body = const {};
try {
final decoded = jsonDecode(error.body ?? '');
if (decoded is Map<String, dynamic>) body = decoded;
} catch (_) {
// Not JSON. The account details are simply unavailable, which is still a
// better outcome than failing to report the rejection at all.
}
const what = 'An SSO required response';
return SsoRequiredException(
provider: optionalString(body, 'provider', what),
accountKey: optionalString(body, 'accountKey', what),
displayName: optionalString(body, 'displayName', what),
);
}