Home > Mobile >  My api won't return the payload on the flutter homepage from my FastAPI endpoint after signing
My api won't return the payload on the flutter homepage from my FastAPI endpoint after signing

Time:06-05

I am sorry for the noob question, but is there a way to get my endpoint to return text with my username and other data from the json file in my flutter homepage just after logging in? the login endpoint works and i can see from the logs that i get INFO: 127.0.0.1:52744 - "POST /auth/login HTTP/1.1" 200 OK login button, but get a INFO:127.0.0.1:52746 - "GET /auth/me HTTP/1.1" 401 Unauthorized when the flutter page changes to the homepage. I have tried including the flutter_secure_stroage to store the jwt token gotten at login but still get an error. Is this error from my endpoint? or is it from my frontend Flutter? THank you.

Here is my login endpoint:

@router.post("/login", response_model=Token)
def login_for_access_token(
    form_data: OAuth2PasswordRequestForm = Depends(), db: Session = Depends(get_db)
):
    vendor = authenticate_vendor(form_data.username, form_data.password, db)
    if not vendor:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Incorrect username or password",
        )
    accesss_token_expires = timedelta(minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES)
    accesss_token = create_access_token(
        data={"sub": vendor.email}, expires_delta=accesss_token_expires
    )
    return {"access_token": accesss_token, "token_type": "bearer"}


oauth_scheme = OAuth2PasswordBearer(tokenUrl="/auth/login")


def get_current_user_from_token(
    token: str = Depends(oauth_scheme), db: Session = Depends(get_db)
):
    credentials_exception = HTTPException(
        status_code=status.HTTP_401_UNAUTHORIZED,
        detail="Could not validate credentials",
    )
    try:
        payload = jwt.decode(
            token, settings.SECRET_KEY, algorithms=[settings.ALGORITHM]
        )
        username: str = payload.get("sub")
        print("username/email extracted is", username)
        if username is None:
            raise credentials_exception
    except JWTError:
        raise credentials_exception
    vendor = get_vendor(username=username, db=db)
    if vendor is None:
        raise credentials_exception
    return vendor

here is the auth/me endpoint:


@router.get("/me")
def get_current_user_from_token(
    token: str = Depends(oauth_scheme), db: Session = Depends(get_db)
):
    credentials_exception = HTTPException(
        status_code=status.HTTP_401_UNAUTHORIZED,
        detail="Could not validate credentials",
    )
    try:
        payload = jwt.decode(
            token, settings.SECRET_KEY, algorithms=[settings.ALGORITHM]
        )
        username: str = payload.get("sub")
        print("username/email extracted is", username)
        if username is None:
            raise credentials_exception
    except JWTError:
        raise credentials_exception
    vendor = get_vendor(username=username, db=db)
    if vendor is None:
        raise credentials_exception
    return vendor

Now for my frontend flutter,

This is my Main.dart on flutter:

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  Future<String> get jwtOrEmpty async {
    var jwt = await storage.read(key: "jwt");
    if (jwt == null) return "";
    return jwt;
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Authentication Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: FutureBuilder(
          future: jwtOrEmpty,
          builder: (context, snapshot) {
            if (!snapshot.hasData) return CircularProgressIndicator();
            if (snapshot.data != "") {
              var str = snapshot.data;
              var jwt = str.toString().split(".");

              if (jwt.length != 3) {
                return LoginPage();
              } else {
                var payload = json.decode(
                    ascii.decode(base64.decode(base64.normalize(jwt[1]))));
                if (DateTime.fromMillisecondsSinceEpoch(payload["exp"] * 1000)
                    .isAfter(DateTime.now())) {
                  return HomePage(str.toString(), payload);
                } else {
                  return LoginPage();
                }
              }
            } else {
              return LoginPage();
            }
          }),
    );
  }
}

This is the homepage:

class HomePage extends StatelessWidget {
  const HomePage(this.jwt, this.payload, {Key? key}) : super(key: key);

  factory HomePage.fromBase64(String jwt) => HomePage(
      jwt,
      json.decode(
          ascii.decode(base64.decode(base64.normalize(jwt.split(".")[1])))));

  final String jwt;
  final Map<String, dynamic> payload;

  @override
  Widget build(BuildContext context) => Scaffold(
        appBar: AppBar(title: const Text("Secret Data Screen")),
        body: Center(
          child: FutureBuilder(
              future: http.read(Uri.parse('$SERVER_IP/auth/me'),
                  headers: {"Authorization": jwt}),
              builder: (context, snapshot) => snapshot.hasData
                  ? Column(
                      children: <Widget>[
                        Text("${payload['username']}, here's the data:"),
                        Text(snapshot.data.toString(),
                            style: Theme.of(context).textTheme.displayLarge)
                      ],
                    )
                  : snapshot.hasError
                      ? const Text("error occurred")
                      : const CircularProgressIndicator()),
        ),
      );
}

This is the login.dart:

class LoginPage extends StatelessWidget {
  final TextEditingController _usernameController = TextEditingController();
  final TextEditingController _passwordController = TextEditingController();

  LoginPage({Key? key}) : super(key: key);

  void displayDialog(context, title, text) => showDialog(
        context: context,
        builder: (context) =>
            AlertDialog(title: Text(title), content: Text(text)),
      );

  Future<String?> attemptLogIn(String username, String password) async {
    var res = await http.post(Uri.parse("$SERVER_IP/auth/login"),
        body: {"username": username, "password": password});
    if (res.statusCode == 200) return res.body;
    return null;
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: const Text("Log In"),
        ),
        body: Padding(
          padding: const EdgeInsets.all(8.0),
          child: Column(
            children: <Widget>[
              TextField(
                controller: _usernameController,
                decoration: const InputDecoration(labelText: 'Username'),
              ),
              TextField(
                controller: _passwordController,
                obscureText: true,
                decoration: const InputDecoration(labelText: 'Password'),
              ),
              TextButton(
                  onPressed: () async {
                    var username = _usernameController.text;
                    var password = _passwordController.text;
                    var jwt = await attemptLogIn(username, password);
                    if (jwt != null) {
                      storage.write(key: "jwt", value: jwt);
                      Navigator.push(
                          context,
                          MaterialPageRoute(
                              builder: (context) => HomePage.fromBase64(jwt)));
                    } else {
                      displayDialog(context, "An Error Occurred",
                          "No account was found matching that username and password");
                    }
                  },
                  child: const Text("Log In")),
            ],
          ),
        ));
  }
}

CodePudding user response:

/login returns {"access_token": accesss_token, "token_type": "bearer"} string, which is saved, while FutureBuilder for jwtOrEmpty expects a token not full response.

Also /me expects bearer type, meaning something like this {"Authorization": "Bearer $jwt"}

  • Related