diff --git a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
index a28140cfdb3ff9b7a11a9497b84546d615db2afa..12f056a58e55a3eab7dc15a86eed72a1d6f4576b 100644
--- a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
+++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1020"
+   LastUpgradeVersion = "1030"
    version = "1.3">
    <BuildAction
       parallelizeBuildables = "YES"
diff --git a/ios/Runner.xcodeproj/xcshareddata/xcschemes/development.xcscheme b/ios/Runner.xcodeproj/xcshareddata/xcschemes/development.xcscheme
index 070dcc01088fafcb8456d97746866c29febf81b4..2e31fa212bc008b370f1068d3bb072bb8e09f625 100644
--- a/ios/Runner.xcodeproj/xcshareddata/xcschemes/development.xcscheme
+++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/development.xcscheme
@@ -23,7 +23,7 @@
       </BuildActionEntries>
    </BuildAction>
    <TestAction
-      buildConfiguration = "Debug"
+      buildConfiguration = "Debug-development"
       selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
       selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
       shouldUseLaunchSchemeArgsEnv = "YES">
@@ -65,7 +65,7 @@
       </AdditionalOptions>
    </LaunchAction>
    <ProfileAction
-      buildConfiguration = "Release"
+      buildConfiguration = "Release-development"
       shouldUseLaunchSchemeArgsEnv = "YES"
       savedToolIdentifier = ""
       useCustomWorkingDirectory = "NO"
@@ -82,10 +82,10 @@
       </BuildableProductRunnable>
    </ProfileAction>
    <AnalyzeAction
-      buildConfiguration = "Debug">
+      buildConfiguration = "Debug-development">
    </AnalyzeAction>
    <ArchiveAction
-      buildConfiguration = "Debug-development"
+      buildConfiguration = "Release-development"
       revealArchiveInOrganizer = "YES">
    </ArchiveAction>
 </Scheme>
diff --git a/ios/Runner.xcodeproj/xcshareddata/xcschemes/production.xcscheme b/ios/Runner.xcodeproj/xcshareddata/xcschemes/production.xcscheme
index 9bacab5a653ddf4d641628abf214ab299a3be56a..041708fdd109c4df750e65bd03151facc85f8c26 100644
--- a/ios/Runner.xcodeproj/xcshareddata/xcschemes/production.xcscheme
+++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/production.xcscheme
@@ -23,7 +23,7 @@
       </BuildActionEntries>
    </BuildAction>
    <TestAction
-      buildConfiguration = "Debug"
+      buildConfiguration = "Debug-production"
       selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
       selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
       shouldUseLaunchSchemeArgsEnv = "YES">
@@ -65,7 +65,7 @@
       </AdditionalOptions>
    </LaunchAction>
    <ProfileAction
-      buildConfiguration = "Release"
+      buildConfiguration = "Release-production"
       shouldUseLaunchSchemeArgsEnv = "YES"
       savedToolIdentifier = ""
       useCustomWorkingDirectory = "NO"
@@ -82,7 +82,7 @@
       </BuildableProductRunnable>
    </ProfileAction>
    <AnalyzeAction
-      buildConfiguration = "Debug">
+      buildConfiguration = "Debug-production">
    </AnalyzeAction>
    <ArchiveAction
       buildConfiguration = "Release-production"
diff --git a/lib/config.dart b/lib/config.dart
index cbbe9229109a57999eabcdd92f20e05d7fd3a5f3..2194fde776d6cc4645101506dbdaedaaa5053f08 100644
--- a/lib/config.dart
+++ b/lib/config.dart
@@ -9,6 +9,7 @@ class Config {
   static const HOSTS = [
     'https://demo1.vereign.com',
     'https://demo2.vereign.com',
+    'https://app.vereign.com',
     'https://rosengeorgiev.dev.vereign.com',
     'https://borisdimitrov.dev.vereign.com',
     'https://integration.vereign.com',
diff --git a/lib/src/app.dart b/lib/src/app.dart
index 3e2b29d60263127e11faa00ddc88778a5d9eabd1..d9ea905180a204cffb1468c50d31d1ef66ac2420 100644
--- a/lib/src/app.dart
+++ b/lib/src/app.dart
@@ -1,4 +1,6 @@
 // app.dart
+import '../config.dart';
+import 'error-alert.dart';
 import 'screens/splashscreen.dart';
 import 'package:flutter/material.dart';
 import 'screens/home.dart';
@@ -6,9 +8,25 @@ import 'package:flutter/services.dart';
 import 'dart:async';
 import 'dart:developer';
 import 'package:shared_preferences/shared_preferences.dart';
+import 'package:flutter_web_browser/flutter_web_browser.dart';
+import 'dart:convert';
+import 'package:url_launcher/url_launcher.dart';
+import 'package:flutter_app_auth_wrapper/flutter_app_auth_wrapper.dart';
+import 'dart:io';
 
 import 'package:uni_links/uni_links.dart';
 
+enum AppMode {
+  Default,
+  Authorization,
+}
+
+enum Screen {
+  App,
+  OAuth,
+  Dashboard
+}
+
 class App extends StatelessWidget {
   Future<Widget> initApplication() async {
     Uri initialUri;
@@ -41,8 +59,6 @@ class App extends StatelessWidget {
           navigateAfterFuture: initApplication,
         )
     );
-
-
   }
 }
 
@@ -58,15 +74,83 @@ class MainApp extends StatefulWidget {
 class _MainAppState extends State<MainApp> {
   StreamSubscription _sub;
 
-  String _appMode = "";
+  /// "Default" when you open app, "Authorization" when app initiated
+  /// from third party app
+  AppMode _appMode;
 
   // Url of the app which invoked OAuth
   String _invokerURL;
-  String _host;
+
+  String _host = Config.appFlavor == Flavor.DEVELOPMENT ? Config.HOSTS[0] : Config.DEFAULT_APP_HOST;
+
+  Screen _currentScreen = Screen.App;
+
+  bool _buttonsHidden = true;
 
   @override
   initState() {
     super.initState();
+
+    // Set up app host
+    if (widget.initialHost != null) {
+      setState(() {
+        _host = widget.initialHost;
+      });
+    }
+
+    // Subscribe to authorization events
+    FlutterAppAuthWrapper.eventStream().listen((data) async {
+      var token = json.decode(data.toString())["access_token"];
+      setScreen(Screen.App);
+
+      try {
+        await launch("$_invokerURL?token=$token&host=$_host");
+      } catch (e) {
+        showErrorAlert(context, 'Unable to open URL $_invokerURL', openVereign);
+      }
+
+      revealButtons(1);
+    }, onError: (error) {
+      log("Err $error");
+
+      String errorMessage = error.message;
+      String errorDetails  = "";
+
+      try {
+        errorDetails = json.decode(error.details)["errorDescription"];
+      } catch (e) {
+        errorDetails = error.details;
+      }
+
+      if (
+        // Handle cancellation for Android
+        errorDetails == 'User cancelled flow' ||
+        // Handle cancellation for iOS
+        errorMessage.toLowerCase().contains("the operation couldn")
+      ) {
+        if (Platform.isAndroid) {
+          // Reveal after three seconds
+          revealButtons(3);
+
+          // Open only for android, because iOS will show the same alert as
+          // was for Auth request
+          openVereign();
+        } else {
+          setScreen(Screen.App);
+          revealButtons(0);
+        }
+      } else {
+        showErrorAlert(context, Platform.isAndroid ? errorDetails : errorMessage, openVereign);
+        setScreen(Screen.App);
+        revealButtons(0);
+      }
+    });
+
+
+    // Show buttons after timeout
+    revealButtons(3);
+
+
     initUniLinks();
   }
 
@@ -77,31 +161,100 @@ class _MainAppState extends State<MainApp> {
   }
 
   Future<Null> initUniLinks() async {
-    updateAppMode(widget.initialUri);
+    handleLinkChange(widget.initialUri);
 
     _sub = getUriLinksStream().listen((Uri uri) {
-      updateAppMode(uri);
+      handleLinkChange(uri);
     }, onError: (err) {
       log('got err: $err');
     });
   }
 
-  updateAppMode(Uri uri) {
+  hideButtons() {
+    if (_revealTimer != null && _revealTimer.isActive) {
+      _revealTimer.cancel();
+    }
+
+
+    setState(() {
+      _buttonsHidden = true;
+    });
+  }
+
+  Timer _revealTimer;
+  revealButtons(delay) {
+    _revealTimer = Timer(
+        Duration(seconds: delay),
+            () {
+          setState(() {
+            _buttonsHidden = false;
+          });
+        }
+    );
+  }
+
+  handleLinkChange(Uri uri) {
     if (uri?.path == "/authorize") {
       setState(() {
-        _appMode = "oauth";
+        _appMode = AppMode.Authorization;
         _invokerURL = uri.queryParameters["invokerUrl"];
       });
+
+      startOAuth();
     } else {
       setState(() {
-        _appMode = "app";
+        _appMode = AppMode.Default;
       });
+
+      openVereign();
+    }
+  }
+
+  setScreen(Screen screen) {
+    setState(() {
+      _currentScreen = screen;
+    });
+  }
+
+  openVereign() {
+    setScreen(Screen.Dashboard);
+
+    FlutterWebBrowser.openWebPage(url: _host, androidToolbarColor: Color(0xFFd51d32));
+  }
+
+  startOAuth() {
+    if (_currentScreen == Screen.OAuth) {
+      return;
     }
+
+    // Hide buttons so they wont blink after we close or finish oauth
+    hideButtons();
+
+    setScreen(Screen.OAuth);
+
+    var params = Config.getOAuthParams(host: _host);
+
+    FlutterAppAuthWrapper.startAuth(
+      AuthConfig(
+        clientId: params["clientId"],
+        clientSecret: params["clientSecret"],
+        redirectUrl: params["redirectUrl"],
+        state: "login",
+        prompt: "consent",
+        endpoint: AuthEndpoint(
+            auth: params["authEndpoint"], token: params["tokenEndpoint"]),
+        scopes: [
+          "user_account_status",
+          "user_territory",
+          "user_profile"
+        ],
+      ),
+    );
   }
 
-  setMode(String mode) {
+  setHost(String host) {
     setState(() {
-      _appMode = mode;
+      _host = host;
     });
   }
 
@@ -111,9 +264,11 @@ class _MainAppState extends State<MainApp> {
       appBar: new AppBar(title: Text("Vereign")),
       body: Home(
         mode: _appMode,
-        invokerURL: _invokerURL,
-        setMode: setMode,
-        host: widget.initialHost
+        host: _host,
+        setHost: setHost,
+        openDashboardClick: openVereign,
+        authorizeClick: startOAuth,
+        buttonsHidden: _buttonsHidden
       )
     );
   }
diff --git a/lib/src/error-alert.dart b/lib/src/error-alert.dart
new file mode 100644
index 0000000000000000000000000000000000000000..a3fd300440bb05e7f45e2219fc518cf05668bb17
--- /dev/null
+++ b/lib/src/error-alert.dart
@@ -0,0 +1,22 @@
+import 'package:flutter/material.dart';
+
+Future<void> showErrorAlert(context, errorString, callback) {
+  return showDialog<void>(
+    context: context,
+    builder: (BuildContext context) {
+      return AlertDialog(
+        title: Text('Authorization error'),
+        content: Text(errorString),
+        actions: <Widget>[
+          FlatButton(
+            child: Text('Open Dashboard'),
+            onPressed: () async {
+              Navigator.of(context).pop();
+              callback();
+            },
+          ),
+        ],
+      );
+    },
+  );
+}
\ No newline at end of file
diff --git a/lib/src/screens/home.dart b/lib/src/screens/home.dart
index a336e144994788c2e649399288ebdb6afc92cf78..c5e8e88309250d99b2cff53ade6c8efb6f5073dd 100644
--- a/lib/src/screens/home.dart
+++ b/lib/src/screens/home.dart
@@ -1,160 +1,58 @@
 import 'package:flutter/material.dart';
-import 'package:flutter_web_browser/flutter_web_browser.dart';
-import 'package:flutter_app_auth_wrapper/flutter_app_auth_wrapper.dart';
-import 'package:url_launcher/url_launcher.dart';
-import 'dart:developer';
-import 'dart:convert';
 import 'dart:async';
 import 'package:shared_preferences/shared_preferences.dart';
 
 import '../../config.dart';
+import '../app.dart';
 
 class Home extends StatefulWidget {
-  Home({@required this.mode, @required this.invokerURL, @required this.setMode, @required this.host});
-  final String mode;
-  final String invokerURL;
+  Home({
+    @required this.mode,
+    @required this.host,
+    @required this.setHost,
+    @required this.authorizeClick,
+    @required this.openDashboardClick,
+    @required this.buttonsHidden,
+  });
+
+  final AppMode mode;
   final String host;
-  final void Function(String) setMode;
+  final bool buttonsHidden;
+  final void Function(String) setHost;
+  final void Function() openDashboardClick;
+  final void Function() authorizeClick;
 
   @override
   _HomeState createState() => _HomeState();
 }
 
 class _HomeState extends State<Home> {
-  String _host = Config.appFlavor == Flavor.DEVELOPMENT ? Config.HOSTS[0] : Config.DEFAULT_APP_HOST;
-  bool _hidden = true;
-
   @override
   initState() {
     super.initState();
-    if (widget.host != null) {
-      setState(() {
-        _host = widget.host;
-      });
-    }
-
-    showMode(widget.mode);
-
-    FlutterAppAuthWrapper.eventStream().listen((data) {
-      var token = json.decode(data.toString())["access_token"];
-      _showAlert(token);
-      widget.setMode("");
-    }, onError: (error) {
-      log("Err $error");
-      widget.setMode("");
-    });
-
-    Timer(
-        Duration(seconds: 3),
-        () {
-          setState(() {
-            _hidden = false;
-          });
-        }
-    );
-  }
-
-  Future<void> _showAlert(token) {
-    return showDialog<void>(
-      context: context,
-      builder: (BuildContext context) {
-        return AlertDialog(
-          title: Text('Authorization success'),
-          actions: <Widget>[
-            FlatButton(
-              child: Text('Go back'),
-              onPressed: () async {
-                Navigator.of(context).pop();
-
-                log("Open ${widget.invokerURL}");
-                try {
-                  await launch("${widget.invokerURL}?token=$token&host=$_host");
-                } catch (e) {
-                  log("Error launching url ${widget.invokerURL}");
-                }
-              },
-            ),
-          ],
-        );
-      },
-    );
-  }
-
-  @override
-  void didUpdateWidget(Home oldWidget) {
-    // this method IS called when parent widget passes new "props"
-    // unlike React, this method IS called _before_ the build
-    // unlike React, this method ISN'T called after setState()
-
-    if (widget.host != oldWidget.host && widget.host != null) {
-      setState(() {
-        _host = widget.host;
-      });
-    }
-
-    if (widget.mode != oldWidget.mode) {
-      showMode(widget.mode);
-    }
-
-    super.didUpdateWidget(oldWidget);
-  }
-
-  showMode(mode) {
-    if (mode == "app") {
-      openVereign();
-    } else if (mode == "oauth") {
-      startOAuth();
-    }
-  }
-
-  openVereign() {
-    FlutterWebBrowser.openWebPage(url: _host, androidToolbarColor: Color(0xFFd51d32));
-  }
-
-  startOAuth() {
-    var params = Config.getOAuthParams(host: _host);
-
-    FlutterAppAuthWrapper.startAuth(
-      AuthConfig(
-        clientId: params["clientId"],
-        clientSecret: params["clientSecret"],
-        redirectUrl: params["redirectUrl"],
-        state: "login",
-        prompt: "consent",
-        endpoint: AuthEndpoint(
-            auth: params["authEndpoint"], token: params["tokenEndpoint"]),
-        scopes: [
-          "user_account_status",
-          "user_territory",
-          "user_profile"
-        ],
-      ),
-    );
   }
 
-
-
   @override
   Widget build(BuildContext context) {
-    if (_hidden) {
+    if (widget.buttonsHidden) {
       return Scaffold();
     }
 
     var children = <Widget>[
-      _urlButton(context, "Open Dashboard", openVereign),
-      _urlButton(context, "Authorize with Vereign", startOAuth)
+      _urlButton(context, "Open Dashboard", widget.openDashboardClick),
     ];
 
+    if (widget.mode == AppMode.Authorization) {
+      children.add(_urlButton(context, "Authorize with Vereign", widget.authorizeClick));
+    }
+
     if (Config.appFlavor == Flavor.DEVELOPMENT) {
       children.add(
         wrapInContainer(
           DropdownButton<String>(
-            value: _host,
+            value: widget.host,
             onChanged: (String newValue) async {
-              setState(() {
-                _host = newValue;
-              });
-
+              widget.setHost(newValue);
               final prefs = await SharedPreferences.getInstance();
               prefs.setString("host", newValue);
             },