Skip to content

Instantly share code, notes, and snippets.

Forked from talk2MeGooseman/index.js
Created August 29, 2020 13:26
Show Gist options
  • Save Alynva/2430c23bc305c78ff94dd52ee1a1bd76 to your computer and use it in GitHub Desktop.
Save Alynva/2430c23bc305c78ff94dd52ee1a1bd76 to your computer and use it in GitHub Desktop.
Firebase Cloud Function 3rd Party Oauth Flow For The Web
const functions = require('firebase-functions');
var admin = require("firebase-admin");
const cookieParser = require('cookie-parser');
const crypto = require('crypto');
var serviceAccount = require("./service-account.json");
const APP_NAME = "twitch-playground";
credential: admin.credential.cert(serviceAccount),
databaseURL: ""
const OAUTH_REDIRECT_URI = `https://localhost:5000/popup.html`;
const OAUTH_SCOPES = 'user_read';
* Creates a configured simple-oauth2 client for Twitch.
function twitchOAuth2Client() {
// Twitch OAuth 2 setup
// TODO: Configure the `twitch.client_id` and `twitch.client_secret` Google Cloud environment variables.
const credentials = {
client: {
id: functions.config().twitch.client_id,
secret: functions.config().twitch.client_secret
auth: {
tokenHost: '',
tokenPath: '/oauth2/token'
return require('simple-oauth2').create(credentials);
* Redirects the User to the Twitch authentication consent screen. Also the 'state' cookie is set for later state
* verification.
exports.redirect = functions.https.onRequest((req, res) => {
const oauth2 = twitchOAuth2Client();
cookieParser()(req, res, () => {
const state = req.cookies.state || crypto.randomBytes(20).toString('hex');
console.log('Setting verification state:', state);
res.cookie('state', state.toString(), {maxAge: 3600000, secure: true, httpOnly: true});
const redirectUri = oauth2.authorizationCode.authorizeURL({
redirect_uri: OAUTH_REDIRECT_URI,
state: state
console.log('Redirecting to:', redirectUri);
* Exchanges a given Twitch auth code passed in the 'code' URL query parameter for a Firebase auth token.
* The request also needs to specify a 'state' query parameter which will be checked against the 'state' cookie.
* The Firebase custom auth token, display name, photo URL and Twitch acces token are sent back in a JSONP callback
* function with function name defined by the 'callback' query parameter.
exports.token = functions.https.onRequest((req, res) => {
const oauth2 = twitchOAuth2Client();
try {
cookieParser()(req, res, () => {
console.log('Received verification state:', req.cookies.state);
console.log('Received state:', req.query.state);
if (!req.cookies.state) {
throw new Error('State cookie not set or expired. Maybe you took too long to authorize. Please try again.');
} else if (req.cookies.state !== req.query.state) {
throw new Error('State validation failed');
console.log('Received auth code:', req.query.code);
code: req.query.code,
redirect_uri: OAUTH_REDIRECT_URI
}).then(results => {
console.log('Auth code exchange result received:', results);
// We have an Twitch access token and the user identity now.
const accessToken = results.access_token;
const twitchUserID = 1;
const profilePic = '';
const userName = 'need to do';
// Create a Firebase account and get the Custom Auth Token.
createFirebaseAccount(twitchUserID, userName, profilePic, accessToken).then(firebaseToken => {
// Serve an HTML page that signs the user in and updates the user profile.
res.jsonp({token: firebaseToken});
} catch (error) {
return res.jsonp({error: error.toString});
* Creates a Firebase account with the given user profile and returns a custom auth token allowing
* signing-in this account.
* Also saves the accessToken to the datastore at /twitchAccessToken/$uid
* @returns {Promise<string>} The Firebase custom auth token in a promise.
function createFirebaseAccount(twitchID, displayName, photoURL, accessToken) {
// The UID we'll assign to the user.
const uid = `twitch:${twitchID}`;
// Save the access token tot he Firebase Realtime Database.
const databaseTask = admin.database().ref(`/twitchAccessToken/${uid}`)
// Create or update the user account.
const userCreationTask = admin.auth().updateUser(uid, {
displayName: displayName,
photoURL: photoURL
}).catch(error => {
// If user does not exists we create it.
if (error.code === 'auth/user-not-found') {
return admin.auth().createUser({
uid: uid,
displayName: displayName,
photoURL: photoURL
throw error;
// Wait for all async task to complete then generate and return a custom auth token.
return Promise.all([userCreationTask, databaseTask]).then(() => {
// Create a Firebase custom auth token.
return admin.auth().createCustomToken(uid).then((token) => {
console.log('Created Custom token for UID "', uid, '" Token:', token);
return token;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment