in ReferenceAppKotlin/firebase/server/src/controller/functions/authentication.ts [367:429]
async function handleAuthCodeExchange(
req: functions.Request, res: functions.Response) {
const client_id = req.body.client_id;
const code = req.body.code;
const db = firebase.app().firestore();
// Verify authorization code
const codeSnapshot = await db.collection('authcodes')
.orderBy('created_on', 'desc')
.where('client_id', '==', client_id)
.where('auth_code', '==', code)
.get();
if (codeSnapshot.empty) {
res.status(400).send({
error: 'invalid_grant',
error_description: 'Invalid authorization code'
});
return;
}
// Pick the newest entry in the database, probably redundant (there should
// only be one entry anyway)
const code_info = codeSnapshot.docs[0];
const user_id = code_info.get('user_id');
const created_on = code_info.get('created_on');
const expires_in = code_info.get('expires_in');
// Check if token is expired
if (created_on + expires_in * 1000 < Date.now()) {
res.status(400).send({
error: 'invalid_grant',
error_description: 'Authorization code expired'
});
return;
}
// Generate tokens
const access_token = await generateToken(32, 'token');
const refresh_token = await generateToken(64, 'token');
try {
// Store in database
await db.collection('tokens').add({
client_id: client_id,
user_id: user_id,
scope: [],
refresh_token: refresh_token,
access_token: access_token,
expires_in: ACCESS_TOKEN_EXPIRY,
created_on: Date.now()
});
// Return generated tokens if database write was successful
res.status(200).send({
access_token: access_token,
expires_in: ACCESS_TOKEN_EXPIRY,
refresh_token: refresh_token,
token_type: 'Bearer'
});
} catch (err) {
// Return error if database write was unsuccessful
console.error(err);
res.status(500).send(err);
}
}