init method
Init B2C application. It look for existing accounts and retrieves information.
The tag
argument is used to distinguish which invocation of the init
generated the return callback. The configFileName
argument specifies
the name of the json configuration file in the web/assets folder.
Returns a Future callable from the AzureB2C plugin.
It emits a B2COperationResult with possible results:
- B2COperationState.SUCCESS from B2COperationSource.INIT if init is successful.
- B2COperationState.CLIENT_ERROR from B2COperationSource.INIT if an error occurred. If redirect mode is selected it also emits:
- B2COperationState.SUCCESS from B2COperationSource.POLICY_TRIGGER_INTERACTIVE if the policy flow has been successful after redirection to the app.
- B2COperationState.PASSWORD_RESET from B2COperationSource.POLICY_TRIGGER_INTERACTIVE if the user has requested a password change.
Implementation
Future init(String tag, String configFileName) async {
initializeDateFormatting();
try {
var conf = json.decode(await rootBundle.loadString(configFileName));
BrowserCacheLocation cache = BrowserCacheLocation.sessionStorage;
if (conf.containsKey("cache_location")) {
if (conf["cache_location"] == "localStorage")
cache = BrowserCacheLocation.localStorage;
else if (conf["cache_location"] == "memoryStorage")
cache = BrowserCacheLocation.memoryStorage;
}
String clientId = conf["client_id"];
String redirectURI = conf["redirect_uri"];
if (conf.containsKey("interaction_mode")) {
if (conf["interaction_mode"] == "redirect")
_interactionMode = B2CInteractionMode.REDIRECT;
}
String? defaultAuthority;
List<String> authorities = <String>[];
if (conf.containsKey("authorities")) {
for (Map<String, dynamic> authority in conf["authorities"]) {
if (authority.containsKey("default") &&
authority["default"] == true) {
defaultAuthority = authority["authority_url"];
}
authorities.add(authority["authority_url"]);
}
}
_setHostAndTenantFromAuthority(defaultAuthority!);
if (conf.containsKey("default_scopes")) {
for (String scope in conf["default_scopes"]) {
_defaultScopes.add(scope);
}
}
_configuration = Configuration()
..cache = (CacheOptions()..cacheLocation = cache)
..auth = (BrowserAuthOptions()
..authority = defaultAuthority
..clientId = clientId
..redirectUri = redirectURI
..knownAuthorities = authorities);
_b2cApp = PublicClientApplication(_configuration!);
_loadAllAccounts();
if (window.localStorage.containsKey(_B2C_PLUGIN_LAST_ACCESS)) {
try {
B2CAccessToken lastAccessToken = B2CAccessToken.fromJson(
json.decode(window.localStorage[_B2C_PLUGIN_LAST_ACCESS]!));
if (_users.containsKey(lastAccessToken.subject)) {
_accessTokens[lastAccessToken.subject] = lastAccessToken;
_emitCallback(B2COperationResult(
tag,
B2COperationSource.POLICY_TRIGGER_INTERACTIVE,
B2COperationState.SUCCESS));
}
} catch (exception) {
log("SessionStorage temp access token parse failed: $exception",
name: tag);
} finally {
window.localStorage.remove(_B2C_PLUGIN_LAST_ACCESS);
}
}
if (_lastHash != null && _lastHash != "#/") {
if (_lastHash!.contains(_B2C_PASSWORD_CHANGE)) {
window.sessionStorage
.removeWhere((key, value) => key.startsWith("msal"));
_emitCallback(B2COperationResult(
tag,
B2COperationSource.POLICY_TRIGGER_INTERACTIVE,
B2COperationState.PASSWORD_RESET));
return;
} else {
var result = await _b2cApp!.handleRedirectFuture(_lastHash);
if (result != null) {
_users[result.uniqueId] = result.account!;
_accessTokens[result.uniqueId] = _accessTokenFromAuthResult(result);
// MSAL seams to reload the page after the handleRedirectFuture is
// completed, so we temporarly store the access token in the local
// storage to use it later, e.g. see code before.
window.localStorage[_B2C_PLUGIN_LAST_ACCESS] =
json.encode(_accessTokenFromAuthResult(result));
}
}
_lastHash = null;
}
_emitCallback(B2COperationResult(
tag, B2COperationSource.INIT, B2COperationState.SUCCESS));
} catch (ex) {
_emitCallback(B2COperationResult(
tag, B2COperationSource.INIT, B2COperationState.CLIENT_ERROR));
}
}