I'm trying to lock a deal in firebase for a specific user. Client will lock a price that will be the same for everyone at that exact second. When the client locks the price I want to check whether or not the price is the same as it is on the server (so it won't get cracked), or is there a better approach?
But I can't seem to get it to work.
My flutter function:
// dealId could be: "md4b6c3uoe75zt2zmj893" and clientPrice could be: 82.15
Future<bool> lockDeal(String dealId, double clientPrice) async {
print('======= DIAGNOSE: HTTP LOCKDEAL FUNCTIE GESTART =======');
print('DealID: $dealId, ClientPrice: $clientPrice');
if (_auth == null || _auth!.currentUser == null) {
print('DIAGNOSE FOUT: Geen gebruiker ingelogd');
return false;
}
try {
// 1. Haal een verse ID token op
final idToken = await _auth!.currentUser!.getIdToken(true);
// NULL CHECK: Controleer of de token daadwerkelijk is opgehaald
if (idToken == null) {
print('DIAGNOSE FOUT: Token kon niet worden opgehaald');
return false;
}
// Nu kunnen we veilig substring aanroepen
print('Token verkregen (eerste 20 tekens): ${idToken.substring(0, min(idToken.length, 20))}...');
// 2. Controleer deal beschikbaarheid
final isAvailable = await isDealAvailable(dealId);
if (!isAvailable) {
print('DIAGNOSE FOUT: Deal is niet beschikbaar: $dealId');
return false;
}
// 3. Bouw de URL en headers
final url = 'https://europe-west1-{My-Project-Name}.cloudfunctions/lockDeal';
final headers = {
'Content-Type': 'application/json',
'Authorization': 'Bearer $idToken'
};
final body = jsonEncode({
'dealId': dealId
});
print('HTTP aanvraag: URL=$url');
print('HTTP aanvraag: Headers=${headers.toString().replaceAll(idToken, "[TOKEN VERBORGEN]")}');
print('HTTP aanvraag: Body=$body');
// 4. Maak de HTTP-aanvraag
final response = await http.post(
Uri.parse(url),
headers: headers,
body: body
);
print('HTTP respons status: ${response.statusCode}');
print('HTTP respons body: ${response.body}');
// 5. Verwerk de respons
if (response.statusCode == 200) {
final responseData = jsonDecode(response.body);
if (responseData['success'] == true) {
final serverPrice = responseData['price'] is num ?
(responseData['price'] as num).toDouble() : clientPrice;
print('Deal vergrendeld! Server prijs: $serverPrice');
return true;
} else {
print('Functie gaf success=false: ${responseData['message'] ?? 'Geen foutmelding'}');
return false;
}
} else {
print('HTTP fout: ${response.statusCode}');
print('Fout details: ${response.body}');
return false;
}
} catch (e) {
print('Algemene fout bij vergrendelen deal: $e');
return false;
}
}
And this is my function in the index.js file:
exports.lockDeal = functions.region('europe-west1').https.onRequest(async (req, res) => {
// Strikt CORS beleid
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'POST');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
// Preflight direct afhandelen
if (req.method === 'OPTIONS') {
return res.status(204).send('');
}
// Alleen POST toegestaan
if (req.method !== 'POST') {
return res.status(405).json({ success: false, message: 'Method not allowed' });
}
try {
// Strikte autorisatie check
const authHeader = req.headers.authorization;
if (!authHeader?.startsWith('Bearer ')) {
console.error('Missing auth header');
return res.status(401).json({ success: false, message: 'Unauthorized' });
}
const idToken = authHeader.split('Bearer ')[1];
const decodedToken = await admin.auth().verifyIdToken(idToken);
const userId = decodedToken.uid;
// Body validatie
if (!req.body?.dealId) {
return res.status(400).json({ success: false, message: 'Bad request' });
}
const dealId = req.body.dealId;
const dealRef = admin.database().ref(`deals/${dealId}`);
// Transactionele update
const result = await dealRef.transaction((deal) => {
if (!deal) return;
if (deal.status === 'locked') return deal;
deal.status = 'locked';
deal.lockedByUserId = userId;
deal.lockedPrice = calculateCurrentPrice(deal);
deal.lockedAt = Date.now();
return deal;
});
if (!resultmitted) {
return res.status(409).json({
success: false,
message: result.snapshot.val()?.status === 'locked'
? 'Deal already locked'
: 'Conflict'
});
}
// Firestore update
await admin.firestore().collection('locked_deals').doc(dealId).set({
...result.snapshot.val(),
lockedAt: admin.firestore.FieldValue.serverTimestamp(),
});
return res.json({
success: true,
dealId: dealId,
price: result.snapshot.val().lockedPrice
});
} catch (error) {
console.error('Critical error:', error);
return res.status(500).json({
success: false,
message: 'Internal server error'
});
}
})
The error I'm getting is:
ClientException: The authentication challenge sent by the server is not correctly formatted.
Anyone that know how I can fix this? Or at least push me in the right direction?
Full output:
I/flutter (16861): ======= DIAGNOSE: HTTP LOCKDEAL FUNCTION StARTED =======
I/flutter (16861): DealID: md4b6c3uoe75zt2zmj893, ClientPrice: 82.15
W/System (16861): Ignoring header X-Firebase-Locale because its value was null.
D/TrafficStats(16861): tagSocket(123) with statsTag=0xffffffff, statsUid=-1
D/FirebaseAuth(16861): Notifying id token listeners about user ( {some id} ).
I/flutter (16861): Token received: {some api code}...
I/flutter (16861): HTTP aanvraag: URL=https://europe-west1-{My-Project-Here}.cloudfunctions/lockDeal
I/flutter (16861): HTTP request: Headers={Content-Type: application/json, Accept: application/json, Authorization: Bearer [TOKEN VERBORGEN]}
I/flutter (16861): HTTP request: Body={"dealId":"md4b6c3uoe75zt2zmj893"}
I/flutter (16861): General error when locking deal: ClientException: The authentication challenge sent by the server is not correctly formatted.
I removed the api and project-name for privacy reasons.