If we want to open the Home Assistant web interface from within our application without having to log in again to Home Assistant, we can use External Authentication provided by Home Assistant.
The idea is to use jschannel to communicate between the Flutter WebView and the Home Assistant web interface. When we open Home Assistant from the WebView, it will invoke the jschannel named getExternalAuth
, which we need to define in the code when initializing the WebView. Then, the getExternalAuth
function should return the access token back to the Home Assistant web interface for further usage. If the token is correct, we can access the Home Assistant web interface without logging in.
Based on the aforementioned concept, the workflow would be as follows:
- Create a Long-Lived Access Token from the user settings page in Home Assistant.
- Create a jschannel named
getExternalAuth
to be invoked by Home Assistant. - Write code to call the
externalAuthSetToken
jschannel (defined in the Home Assistant web interface) to return the access token created in step 1.
Create Long-Lived Access Tokens
Go to the user settings page, where various settings such as theme color can be found. At the bottom, there is a section for creating Long-Lived Access Tokens. Create a token and copy it before closing the page because it won’t be visible again once closed.
Create jschannel in the Flutter side
controller.addJavaScriptChannel('getExternalAuth',
onMessageReceived: (JavaScriptMessage message) { }
);
Call jschannel back to the Home Assistant side
const token = 'long-lived-access-token';
controller.runJavaScript(
"window.externalAuthSetToken(true, { access_token: '$token', expires_in: 1800 });",
);
Flutter WebView uses WebViewWidget and WebViewController to configure various settings for the WebViewWidget. Therefore, the resulting code would be something like this:
final WebViewController controller = WebViewController();
controller.setJavaScriptMode(JavaScriptMode.unrestricted);
controller.addJavaScriptChannel('getExternalAuth',
onMessageReceived: (JavaScriptMessage message) {
const token = 'long-lived-access-token';
controller.runJavaScript(
"window.externalAuthSetToken(true, { access_token: '$token', expires_in: 1800 });",
);
});
controller.loadRequest(Uri.parse(homeAssistantUrl));
From a technical standpoint, we can add additional logic to decide which user’s long-lived token to send, without necessarily hard-coding the token.