Authenticating Flutter Client with ExpressJS REST API

Viewed 572

I have built a REST api using nodeJS and Typescript and I am performing authentication and authorisation by setting the JWT token as a cookie. I have cors middleware set up as follows on my

const corsOptions: cors.CorsOptions = {
  optionsSuccessStatus: 200,
  origin: "*",
  methods: ['GET', 'PUT', 'POST', 'DELETE', 'OPTIONS'],
  credentials: true
}

app.options('*', cors(corsOptions));
app.use(cors(corsOptions));

I have a flutter client that logs into the API as follows

class LoginRequest {
  String email;
  String password;

  LoginRequest(String email, String password) {
    this.email = email;
    this.password = password;
  }
}

class LoginResponse {
  String username;

  LoginResponse.fromJson(json) {
    this.username = json["username"];
  }
}


Map handleResponse(response) {
  if (response.statusCode == 200) {
    // Note: Here Token is printed correctly
    print("Server responded with response ${response.headers['set-cookie']}"); 

    return json.decode(response.body) as Map;
  } else {
    throw Exception("Server responded with status ${response.statusCode}");
  }
}

Future<LoginResponse> postLogin(LoginRequest loginRequest) async {
  final body = {"email": loginRequest.email, "password": loginRequest.password};
  var bodyEncoded = json.encode(body);
    
  final response = await http
      .post(new Uri.http(apiHost, "/users/login"), body: bodyEncoded, headers: {
    "Content-Type": "application/json",
    "credentials": 'include',
    "Accept": "application/json",
  });
  final jsonResponse = handleResponse(response);
  return LoginResponse.fromJson(jsonResponse);
}

But I cannot seem to get the cookie on the subsequent POST requests. In desperation, I even tried directly sending the token as follows but on the server it comes up undefined. Please help!

Future<AccountInformation> getAccountAllInfos() async {
  final response = await http.get(new Uri.http(apiHost, "/users/me"), headers: {
    "credentials": 'include',
    "Accept": "application/json",
    "set-cookie":
        "token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiI1ZjEyOTY4MTYwNTI1MzRlMWFjZGM4MTQiLCJ1c2VybmFtZSI6InBhd2FuIiwiZW1haWwiOiJwYXdhbkB0b3RvLmNvbSIsIm5hbWUiOiJQYXdhbiIsIm1vYmlsZSI6Ijk4ODYxNDQ2OTMiLCJjcmVhdGVkQXQiOiIyMDIwLTA3LTE4VDA2OjI4OjE3LjE1NloiLCJ1cGRhdGVkQXQiOiIyMDIwLTA3LTE4VDA2OjI4OjE3LjE1NloiLCJfX3YiOjAsImlhdCI6MTU5OTM4OTE5N30.cMVjgj5WntyN0yVjdfDQupyL-dnoDCqEE0rc7oz-k-A"
  });
  final json = handleResponse(response);
  return AccountInformation.fromJson(json);
}

Server side, I use a cookie Extractor to get the cookie and passport to carry out auth:

const JwtStrategy = passportJWT.Strategy

const cookieExtractor = (req: Request) => {
    console.log("Cookie : ", req.cookies.token)
    if (req && req.cookies) {
        const token: string = req.cookies.token
        return token;
    }
    return null
};

const opts = {
    jwtFromRequest: cookieExtractor,
    secretOrKey: process.env.JWT_SECRET || "defaultjwtsecret",
}

passport.use(new JwtStrategy(opts, function (jwt_payload: IUserDocument, done) {
    console.log("Payload:", jwt_payload)
    User.findOne({ username: jwt_payload.username }, function (err, user) {
        if (err) {
            return done(err, false);
        }
        if (user) {
            return done(null, user);
        } else {
            return done(null, false);
        }
    });
}));

And the route is secured as follows:

app.use("/users/me", passport.authenticate("jwt", { session: false }))
0 Answers
Related