Skip to content

Commit 4ea6f44

Browse files
committed
Refactoring
Move basic authentication out into separate function Add error handling
1 parent 83cf323 commit 4ea6f44

File tree

1 file changed

+73
-49
lines changed
  • username-password-auth/functions

1 file changed

+73
-49
lines changed

username-password-auth/functions/index.js

Lines changed: 73 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -38,81 +38,105 @@ const basicAuthRequest = require('request');
3838
* Authenticate the provided credentials returning a Firebase custom auth token.
3939
* `username` and `password` values are expected in the body of the request.
4040
* If authentication fails return a 401 response.
41+
* If the request is badly formed return a 400 response.
42+
* If the request method is unsupported (not POST) return a 403 response.
4143
* If an error occurs log the details and return a 500 response.
4244
*/
4345
exports.auth = functions.https.onRequest((req, res) => {
46+
47+
const handleError = (username, error) => {
48+
console.error({
49+
User: username
50+
}, error);
51+
return res.sendStatus(500);
52+
}
53+
54+
const handleResponse = (username, status, body) => {
55+
console.log({
56+
User: username
57+
}, {
58+
Response: {
59+
Status: status,
60+
Body: body
61+
}
62+
});
63+
if (body) {
64+
return res.status(200).json(body);
65+
}
66+
return res.sendStatus(status);
67+
}
68+
69+
70+
let username = '';
4471
try {
4572
cors(req, res, () => {
4673
// Authentication requests are POSTed, other requests are forbidden
4774
if (req.method !== 'POST') {
48-
return res.sendStatus(403);
75+
return handleResponse(username, 403);
4976
}
50-
let username = req.body.username;
77+
username = req.body.username;
5178
if (!username) {
52-
return res.sendStatus(400);
79+
return handleResponse(username, 400);
5380
}
54-
let password = req.body.password;
81+
const password = req.body.password;
5582
if (!password) {
56-
return res.sendStatus(400);
83+
return handleResponse(username, 400);
5784
}
5885

59-
let creds = {
60-
'auth': {
61-
'user': username,
62-
'pass': password
86+
// TODO(DEVELOPER): In production you'll need to update the `authenticate` function so that it authenticates with your own credentials system.
87+
authenticate(username, password).then(valid => {
88+
if (!valid) {
89+
return handleResponse(username, 401); // Invalid username/password
6390
}
64-
}
65-
66-
// For the purpose of this example use httpbin (https://httpbin.org) for the basic authentication request.
67-
// (Only a password of `Testing123` will succeed)
68-
const authEndpoint = `https://httpbin.org/basic-auth/${username}/Testing123`;
6991

70-
basicAuthRequest(authEndpoint, creds, (error, response, body) => {
71-
let statusCode = response ? response.statusCode : 0;
72-
if (statusCode === 401) { // Invalid username/password
73-
return res.sendStatus(401);
74-
}
75-
if (statusCode !== 200) {
76-
console.log('ERROR: invalid response returned from ', authEndpoint, ' status code ', statusCode);
77-
return res.sendStatus(500);
78-
}
79-
// On success create/update the Firebase account and return the Custom Auth Token.
80-
// - any extra user details can also be created/updated here
81-
createFirebaseAccount(username).then(firebaseToken => {
82-
return res.status(200).json({
92+
// On success return the Firebase Custom Auth Token.
93+
admin.auth().createCustomToken(username).then(firebaseToken => {
94+
return handleResponse(username, 200, {
8395
token: firebaseToken
8496
});
97+
}).catch(error => {
98+
return handleError(username, error);
8599
});
100+
101+
}).catch(error => {
102+
return handleError(username, error);
86103
});
87104
});
88105
} catch ( error ) {
89-
console.log('ERROR:', error);
90-
return res.sendStatus(500);
106+
return handleError(username, error);
91107
}
92108
});
93109

94110
/**
95-
* Creates a Firebase account with the given user id and returns a custom auth token allowing
96-
* signing-in this account.
97-
*
98-
* @returns {Promise<string>} The Firebase custom auth token in a promise.
111+
* Authenticate the provided credentials.
112+
* TODO(DEVELOPER): In production you'll need to update this function so that it authenticates with your own credentials system.
113+
* @returns {Promise<boolean>} success or failure.
99114
*/
100-
function createFirebaseAccount(uid) {
101-
// Create or update the user account.
102-
const userCreationTask = admin.auth().updateUser(uid, {}).catch(error => {
103-
// If user does not exists we create it.
104-
if (error.code === 'auth/user-not-found') {
105-
return admin.auth().createUser({
106-
uid: uid
107-
});
115+
function authenticate(username, password) {
116+
117+
// For the purpose of this example use httpbin (https://httpbin.org) and send a basic authentication request.
118+
// (Only a password of `Testing123` will succeed)
119+
const authEndpoint = `https://httpbin.org/basic-auth/${username}/Testing123`;
120+
const creds = {
121+
'auth': {
122+
'user': username,
123+
'pass': password
108124
}
109-
throw error;
110-
});
111-
// Wait for all async task to complete then generate and return a custom auth token.
112-
return Promise.all([userCreationTask]).then(() => {
113-
// Create a Firebase custom auth token.
114-
const token = admin.auth().createCustomToken(uid);
115-
console.log('Created Custom token for UID "', uid, '" Token:', token);
116-
return token;
125+
}
126+
return new Promise((resolve, reject) => {
127+
basicAuthRequest(authEndpoint, creds, (error, response, body) => {
128+
if (error) {
129+
return reject(error)
130+
}
131+
const statusCode = response ? response.statusCode : 0;
132+
if (statusCode === 401) { // Invalid username/password
133+
return resolve(false);
134+
}
135+
if (statusCode !== 200) {
136+
return reject(Error('invalid response returned from ', authEndpoint, ' status code ', statusCode));
137+
}
138+
return resolve(true);
139+
});
117140
});
141+
118142
}

0 commit comments

Comments
 (0)