I am working on a full stack app using NodeJS and Flutter For Web, at the moment i don't understand how to make safe cookie/token sessions.
The answer i need is how to make an authentication system with Flutter For Web like other Social Networks or Stackoverflow itself.
-
1you can use `dart:html` package to manually save session information to cookie. – Ryosuke Aug 20 '19 at 18:26
-
@Ryosuke where can i find documentation about this package? – Aug 21 '19 at 07:44
-
1[here](https://api.dartlang.org/stable/2.4.1/dart-html/dart-html-library.html) – Ryosuke Aug 21 '19 at 07:47
-
@Ryosuke ok thanks to save the session which class do i need to use? Because i need to safely save the session and make it re-usable even when the page is closed and reopened – Aug 21 '19 at 07:51
-
1use `CookieStore`. – Ryosuke Aug 21 '19 at 08:37
-
2@Ryosuke Can you please guide me to some usage example for CookieStore class. I [googled](https://www.google.com/search?client=firefox-b-d&sxsrf=ACYBGNQ8S_Pp1KzfqJK-N5t1q7heewRj1w%3A1574340719888&ei=b4jWXZnqNZCCrtoP6faGoAk&q=CookieStore+class+example+in+Flutter&oq=CookieStore+class+example+in+Flutter&gs_l=psy-ab.3...88823.91789..91954...0.2..0.216.3075.0j16j2......0....1..gws-wiz.......0i71j33i160j33i21.n4TTw4NyoWU&ved=0ahUKEwjZ3fSarPvlAhUQgUsFHWm7AZQQ4dUDCAo&uact=5) it already but can't find anything useful. – Mudassir Nov 21 '19 at 12:53
-
1Error - `The class 'CookieStore' doesn't have default constructor.` – iAkshay Nov 21 '19 at 12:57
-
1You can use Firebase, or at least get inspiration from it. Once a user is authenticated in flutter with Firebase, just pass `FirebaseAuth.instance.currentUser().getIdToken().token` (it's a JWT token string) to your nodejs app (using for example an HTTP custom header). Now, in the nodejs app, you can verify the passed token using Firebase "VerifyId" server-side API: https://firebase.google.com/docs/auth/admin/verify-id-tokens. Even if you don't like Firebase, the overall principles are still ok. – Simon Mourier Nov 23 '19 at 10:21
3 Answers
Importing dart.html
directly doesn't support from flutter 1.9 : Reference
I came across the package universal_html while digging in for the solution, and its working fine for me. Below is my helper class to store key-value pair locally on web:
import 'package:universal_html/prefer_universal/html.dart';
class WebStorage {
//Singleton
WebStorage._internal();
static final WebStorage instance = WebStorage._internal();
factory WebStorage() {
return instance;
}
String get sessionId => window.localStorage['SessionId'];
set sessionId(String sid) => (sid == null) ? window.localStorage.remove('SessionId') : window.localStorage['SessionId'] = sid;
}
To read,
WebStorage.instance.sessionId;
To write,
WebStorage.instance.sessionId = 'YOUR_CREDENTIAL';
Example:
fetchPost(params, "CMD_USERREGISTRATION").then((result) {
...
APIResponse response = APIResponse(xmlString: result.body);
if (!response.isSuccess()) {
...
return;
}
var sid = response.getSessionId();
if (kIsWeb) {
WebStorage.instance.sessionId = sid;
}
}
main.dart:
@override
Widget build(BuildContext context) {
if (kIsWeb) {
isLogin = WebStorage.instance.sessionId != null;
} else {
isLogin = //check from SharedPreferences;
}
return isLogin ? dashboardPage() : loginPage();
}
UPDATE:
shared_preferences now support web from the version 0.5.6. See also shared_preferences_web

- 1,143
- 1
- 13
- 35
-
Ok but now that i have a sessionId how can i use it? Can you show an example of this class with routes like get or post? – Nov 23 '19 at 07:59
-
-
Both of `Flutter_Secure_Storage` and `Cookie[Secure/HTTPOnly]` options provided for _SECURITY_, the first one provides encrypted storage for Android(and other native platforms) and the second one prevents `JS` to even know about sensible cookies, take this way with your own risk! BUT on other hand, you can just set login state with a simple type like bool(True/Fale) and handle backend responses to check if SessionID/Credential is valid or not... – Mamrezo May 24 '21 at 04:04
-
1Also `shared_preferences` leak the same as the `WebStorage`, for sensible cookies... – Mamrezo May 24 '21 at 04:06
-
How are you guys talking about saving sensitive data with shared_preferences. It explicit says IT'S NOT FOR SAFE/SENSITIVE DATA ! – MarcoFerreira Apr 19 '23 at 10:10
This is an old question but the chosen answer is not totally safe. Using web storage for sensitive information is not safe, for the web.
You should use http-only cookies. Http-only cookies cannot be read via Javascript but the browser automatically sends it to the backend.
Here is example of Nodejs-Express-TypeScript Code;
In this example there two cookies one is http-only, the other one is not. The non-http-only cookie is for checking logged-in situation, if it's valid client assumes the user is logged in. But the actual control is done by the backend.
PS: There is no need to store or send any token, because browser handles it (cookies) automatically.
const cookieConfig = {
httpOnly: true,
secure,
maxAge: 30 * 24 * 60 * 60 * 1000,
signed: secure,
}
const cookieConfigReadable = {
httpOnly: false,
secure,
maxAge: 30 * 24 * 60 * 60 * 1000,
signed: secure,
}
function signToken(unsignedToken: any) {
const token = jwt.sign(unsignedToken, privatekey, {
algorithm: 'HS256',
expiresIn: jwtExpirySeconds,
})
return token
}
const tokenObj = {
UID: userId,
SID: sessionId,
}
const token = signToken(tokenObj)
// sets session info to the http-only cookie
res.cookie('HSINF', token, cookieConfig)
// sets a cookie with expires=false value for client side check.
res.cookie('expired', false, cookieConfigReadable)
But in this approach there is a challenge during debugging, because NodeJS and Flutter Web serves on different ports, you should allow CORS for dev environment.
if (process.env.NODE_ENV === 'dev') {
app.use(
cors({
origin: [
'http://localhost:8080',
'http://127.0.0.1:8080',
],
credentials: true,
}),
)
}
And in Flutter Web you cannot use http.get or http.post directly during debugging, because flutter disables CORS cookies by default.
Here is a workaround for this.
// withCredentials = true is the magic
var client = BrowserClient()..withCredentials = true;
http.Response response;
try {
response = await client.get(
Uri.parse(url),
headers: allHeaders,
);
} finally {
client.close();
}
Also in debugging there is another challenge; many browsers does not allow cookies for localhost, you should use 127.0.0.1 instead. However Flutter Web only runs for certain url and certain port, so here is my VsCode configuration for Flutter to run on 127.0.0.1
{
"name": "project",
"request": "launch",
"type": "dart",
"program": "lib/main.dart",
"args": [
"-d",
"chrome",
"--web-port",
"8080",
"--web-hostname",
"127.0.0.1"
]
}
These were for setting and transferring cookie, below you can find my backend cookie check
const httpOnlyCookie = req.signedCookies.HSINF
const normalCookie = req.signedCookies.expired
if (httpOnlyCookie && normalCookie === 'false') {
token = httpOnlyCookie
}
if (token) {
let decoded: any = null
try {
decoded = jwt.verify(token, privatekey)
} catch (ex) {
Logger.error(null, ex.message)
}
if (decoded) {
//Cookie is valid, get user with the session id
}
}

- 254
- 3
- 6
-
I am trying your work-follow, but Chrome doesn't keep `HttpOnly` cookies in FlutterWeb! It seems just drops them!? – Mamrezo May 29 '21 at 02:46
-
Hi E.C, could you please elaborate your answer a little more? My users log in using the react web site: mysite.com/auth and once logged in, I want to take them to the Flutter web app in mysite.com/profile and I want to pass the authentication data to Flutter or somehow access it. Will your solution work for this usecase? – aytunch Apr 23 '23 at 18:35
-
1@aytunch , yes, as long as they are in the same host, in this case: "mysite.com", it will work. No need to do anything. Cookies are stored in the browser and the browser does not know you are using React or Flutter. But again, in localhost, because the backend and frontend ports are not the same (if you are not using a local proxy) you should add extra workarounds for debugging. – E.C Apr 25 '23 at 03:38
You can encrypt it as you want then use getStorage to store it & it supports all platforms, example:
GetStorage box = GetStorage();
write it:
box.write('jwt', 'value');
read it:
if (box.hasData('jwt')) {
box.read('jwt');
}

- 69,473
- 35
- 181
- 253

- 1,874
- 3
- 17
- 32