67

Not just where (eg: SQLite...) but also how (libs, best specific practices)?

TheMisir
  • 4,083
  • 1
  • 27
  • 37
zeucxb
  • 1,054
  • 1
  • 11
  • 19

4 Answers4

107

You probably don't want to store sensitive data in shared preferences. Instead you might want to look into a plugin like this: https://pub.dartlang.org/packages/flutter_secure_storage

import 'package:flutter_secure_storage/flutter_secure_storage.dart';

// Create storage
final storage = new FlutterSecureStorage();

// Write value 
await storage.write(key: 'jwt', value: token);
Nicodemuz
  • 3,539
  • 2
  • 26
  • 32
  • 14
    flutter_secure_storage does not support web for now. Any other alternative with flutter web support ? – fvisticot Dec 19 '19 at 21:54
  • @fvisticot I know that the question was asked more than a year ago but I leave the answer for posterity. Basically, there is no way to store token in encrypted storage on the web. But IMO it's safe enough to use shared preferences (actually localStorage) as a fallback for the web. – latata May 06 '21 at 19:53
  • An HTTP-only cookie might be safer against XSS than localStorage if your server can provide it. IIRC, these cookies can also be used with fetch as well for SPAs. I'm not a security expert though so please read about this. – Amir Eldor Feb 04 '22 at 18:36
  • 10
    flutter_secure_storage support web , windows, linux, Macos, android and IOS now from april 2022 – Eslam Sameh Ahmed Apr 30 '22 at 15:35
18

As I mentioned on a deleted post, I've been using hive to storage my tokens and other local data. With hive it's possible to create an encrypted box

import 'dart:typed_data';
import 'package:hive/hive.dart';

void main() async {
  var keyBox = await Hive.openBox('encryptionKeyBox');
  if (!keyBox.containsKey('key')) {
    var key = Hive.generateSecureKey();
    keyBox.put('key', key);
  }

  var key = keyBox.get('key') as Uint8List;
  print('Encryption key: $key');

  var encryptedBox = await Hive.openBox('vaultBox', encryptionKey: key);
  encryptedBox.put('secret', 'Hive is cool');
  print(encryptedBox.get('secret'));
}

As mentioned in comments:

The example above stores the encryption key in an unencrypted box. You should NEVER do that.

Important:

  • Only values are encrypted while keys are stored in plaintext.
  • Make sure to store the encryption key securely when your application is closed. With Flutter you can use the flutter_secure_storage or a similar package.
  • There is no check if the encryption key is correct. If it isn't, there may be unexpected behavior.

So, if you don't need any of hive specific features, flutter_secure_storage should be a better option for you.

zeucxb
  • 1,054
  • 1
  • 11
  • 19
  • Can this encrypted box be shared among two apps? – Yudhishthir Singh May 27 '20 at 19:36
  • 5
    You are using an unencrypted box to store the encryption key. Defeats the purpose of using the encrypted box. – Gilbert Nwaiwu Jun 10 '20 at 11:44
  • 2
    As per [Hive documentation](https://docs.hivedb.dev/#/advanced/encrypted_box), when using an encrypted box you'll need to save the encryption key securely. In Flutter, they suggest [flutter_secure_storage](https://pub.dev/packages/flutter_secure_storage#-readme-tab-) so that you can save it. **My suggestion:** Go with this option instead. – Breno Teodoro Jun 16 '20 at 17:55
  • @BrenoTeodoro yes. – zeucxb Jun 17 '20 at 17:21
  • Is secure storage really necessary on mobile and desktop? since in web we commonly store jwt token in a HttpOnly cookie, user can still see the content from dev tools, so I guess that unless for flutter web, you can store the jwt (not user and password, that's sensitive data) anywhere (Hive, SQLite, Get Storage, etc), in android there's a encrypted app-specific location that only your app has access, https://developer.android.com/training/data-storage/app-specific – talski Apr 01 '21 at 03:09
6

I use https://pub.dev/packages/flutter_secure_storage for saving JWT token in local storage.

import 'package:flutter_secure_storage/flutter_secure_storage.dart';

final storage = const FlutterSecureStorage();

// to save token in local storage
await storage.write(key: 'token', value: data.token);

// to get token from local storage
var value = await storage.read(key: 'token');

other tips:

  • Don't forget to re-build your app (sometimes you need to do flutter clean and flutter pub get)
  • make sure cocoapods install properly if you running it in iOS.
  • For installing cocoapods sudo gem install cocoapods
  • For updating cocoapods sudo gem install cocoapods
  • in my case, I need to close and re-open the vscode after installing cocoapods.
prawito hudoro
  • 533
  • 1
  • 5
  • 10
-9

Using https://pub.dartlang.org/packages/shared_preferences is best for you, as it "provides a persistent store for simple data."

Sample code:

import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';

void main() {
  runApp(MaterialApp(
    home: Scaffold(
      body: Center(
      child: RaisedButton(
        onPressed: _getAndSaveToken,
        child: Text('Get token'),
        ),
      ),
    ),
  ));
}

_getAndSaveToken() async {
  SharedPreferences prefs = await SharedPreferences.getInstance();
  String token = await _getTokenFromHttp();
  await prefs.setInt('jwt', token);
}

Future<String> _getTokenFromHttp() async {
  // http code here
}
TruongSinh
  • 4,662
  • 32
  • 52
  • Does use more than one of this options in the same project make sense? – zeucxb Apr 25 '19 at 12:36
  • 27
    The package description itself indicates that "**this plugin must not be used for storing critical data**". It is best fitted for in-app preferences such as turning on/off dark mode. – Breno Teodoro Jun 16 '20 at 17:59