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"}