pocketbase / dart-sdk

PocketBase Dart SDK
https://pub.dev/packages/pocketbase
MIT License
511 stars 51 forks source link

AuthStore JWT not invalidating #22

Closed xFrann closed 1 year ago

xFrann commented 1 year ago

Hello

I use the dart sdk to authenticate the user + Hive in order to store the RecordModel and JWT Token in the local storage for persistent authentication.

On app start, I run a checkData() function that loads the RecordModel and token from the Hive box and uses authStore.save(token, model) to store the data in the pocketbase authstore.

After that however after calling authStore.isValid it returns true even if I invalidate all tokens from the admin portal under token options and press save.

See called function below:

    checkData() async {
    Hive.registerAdapter(PocketRecordModelAdapter());
    var recordbox = await Hive.openBox("record2");
    PocketRecordModel? prm = Hive.box("record2").get("record2");

    if (prm == null) {
      print("PRM IS null, this is the first time launching the app or user never logged in.");
      return;
    }

    print(prm.getData()); // When succesfull, this returns the RecordModel data

    //Here I create a basic RecordModel from the data stored in Hive
    RecordModel userRecord = RecordModel(
        id: prm.id,
        created: prm.created,
        updated: prm.updated,
        collectionId: prm.collectionId,
        collectionName: prm.collectionName,
        expand: {},
        data: prm.data);

    // Save the record in the authstore
    pb.authStore.save(prm.token, userRecord);
    print("model: " + pb.authStore.model.toString());
    print("isvalid?: " + pb.authStore.isValid.toString());
    bool isLoggedIn = pb.authStore.isValid; // THIS IS ALWAYS TRUE EVEN IF INVALIDATED FROM PORTAL

    if (!isLoggedIn) {
      Future.delayed(const Duration(milliseconds: 1000), () => redirect(const Login()));
      return;
    }

    Future.delayed(const Duration(milliseconds: 1000), () => redirect(Dashboard(username: pb.authStore.model.data['username'])));
  }

shouldn't authStore.isValid return false if all tokens have been invalidated from portal? Is there something I'm missing?

I use pocketbase 0.5.0 as a depedency

ganigeorgiev commented 1 year ago

shouldn't authStore.isValid return false if all tokens have been invalidated from portal?

No. authStore.isValid is just a getter to loosely check whether your current/local AuthStore state is "valid" (aka. has a non empty JWT token with valid exp claim). It doesn't perform any server-side requests or validations.

You can call pb.collection('users').authRefresh() to validate and refresh server-side the current AuthStore state. It will throw an error if the current authStore.token is invalid and/or expired.

If you want to "logout" manually the user in your app, you can call pb.authStore.clear().

Please also note that the PocketBase API is completely stateless, aka. there are no sessions (we don't even store the tokens in the database). A request is considered authenticated only if it was send with valid Authorization: TOKEN header (it is added automatically if the AuthStore.isValid is true).

xFrann commented 1 year ago

Thank you for the quick response, I couldn't find the authRefresh() function, now working as expected. Thank you.

NomadicDeveloper22 commented 1 year ago

@xFrann if you don't mind sharing, what is the code for your PocketRecordModelAdapter()?

I'm new to Flutter (long time native dev), and struggling to get Hive to work with pocketbase's authstore.model

xFrann commented 1 year ago

Hello @TheRedSpy15 ,

see the code below for my implementation PocketRecordModel, Please note it doesn't include the expanded field as Hive doesn't have a way (at least for what I know) to store same classes into one another (Store PocketRecordModel into PocketRecordModel) So In case you have relations on the record model and those relations are expanded they will not be stored by hive, you will have to perform an additional request.

import 'package:hive/hive.dart';

part 'record_model.g.dart';

@HiveType(typeId: 0)
class PocketRecordModel {
  @HiveField(0)
  final String id;
  @HiveField(1)
  final String created;
  @HiveField(2)
  final String updated;
  @HiveField(3)
  final String collectionId;
  @HiveField(4)
  final String collectionName;
  @HiveField(5)
  final Map<String, dynamic> data;
  @HiveField(6)
  final String token;
  PocketRecordModel(
      {required this.id,
      required this.created,
      required this.updated,
      required this.collectionId,
      required this.collectionName,
      required this.data,
      required this.token});
}

Hope this helps