Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Firebase auth #220

Open
benjie opened this issue May 2, 2020 · 5 comments
Open

Firebase auth #220

benjie opened this issue May 2, 2020 · 5 comments

Comments

@benjie
Copy link
Member

benjie commented May 2, 2020

graphile/crystal#882 (comment)

@hiepxanh
Copy link

hiepxanh commented Dec 6, 2020

Sir, we really need your help @benjie

@benjie
Copy link
Member Author

benjie commented Dec 7, 2020

I'm afraid I don't use Firebase so can't help you with Firebase issues; I suggest you read through the linked discussion and maybe ask help from someone in that thread.

@kaushalyap
Copy link

@benjie @jdpowell1 Can we please have some docs on integrating Firebase auth since having third party logins improve UX ?

@benjie
Copy link
Member Author

benjie commented Jan 2, 2022

Use whatever docs detail how to use whatever auth you need with Node (e.g. with whatever webserver you’re using like Express, Koa, Fastify, etc), then use the pgSettings function to pass information from your webserver through to your PostgreSQL transaction. PostGraphile doesn’t mind what auth provider you use so long as the details are available from the “request” object in your supported Node HTTP server.

@hiepxanh
Copy link

hiepxanh commented Jan 2, 2022

here is my example, take a look @kaushalyap

/**
 * This is not a production server yet!
 * This is only a minimal backend to get started.
 */

// const express = require('express');
import express from 'express';

const app = express();

app.get('/api', (req, res) => {
  res.send({ message: 'Welcome to graphql!' });
});

// const { postgraphile } = require('postgraphile');
// const cors = require('cors');
// const bodyParser = require('body-parser');
// const admin = require('firebase-admin');
import { postgraphile } from 'postgraphile';
import cors from 'cors';
import bodyParser from 'body-parser';
import admin from 'firebase-admin';

app.use(cors());
// Enable the use of request body parsing middleware
app.use(bodyParser.json());
app.use(
  bodyParser.urlencoded({
    extended: true,
  })
);

// const firebaseConfig = require('./adminsdk.json');
import firebaseConfig from './adminsdk.json';
import { IncomingMessage } from 'http';
admin.initializeApp({
  credential: admin.credential.cert(firebaseConfig as admin.ServiceAccount),
  databaseURL: 'https://your-database-url-here.firebaseio.com',
});

const asyncMiddleware = (fn) => (req, res, next) => {
  Promise.resolve(fn(req, res, next)).catch(next);
};

const checkJwt = async (req, res, next) => {
  try {
    const token = req.headers.authorization?.split('Bearer ')[1];
    if (!token) {
      console.log('no token found');
      next();
    } else {
      const decodedToken = await admin.auth().verifyIdToken(token);
      req['user'] = decodedToken;
      next();
    }
  } catch (error) {
    res.status(401).send(error);
  }
};

app.use('/graphql', asyncMiddleware(checkJwt));

app.use(
  postgraphile(
    'postgres://postgres:admin@localhost:5432/awread_app',
    'public',
    {
      watchPg: true,
      graphiql: true,
      enhanceGraphiql: true,
      // jwtPgTypeIdentifier: 'public.jwt_token',
      // jwtSecret: 'your-secret-here',
      // pgDefaultRole: 'anonymous',
      pgSettings: async (req: IncomingMessage & { user: any }) => {
        console.log('req.user', req.user);
        return checkRole(req);
      },
    }
  )
);

function checkRole(req) {
  if (req.user) {
    if (req.user.role === 'mod') {
      console.log('role is admin');
      return {
        role: 'admin',
        'jwt.claims.user_id': req.user.uid,
      };
    }

    console.log('role is writer');
    return {
      role: 'writer',
      'jwt.claims.user_id': '10f62cca-d75d-4b7c-8869-9ee319819431', // fix user to test
      // req.user.uid,
    };
  } else {
    console.warn('failed to authenticate, using role default (anonymous)');
    // role null will be using default role of Postgraphile
    return {
      role: 'writer',
      'jwt.claims.user_id': '10f62cca-d75d-4b7c-8869-9ee319819431', // fix user to test
    };
  }
}

app.post('/setCustomClaims', (req, res) => {
  // Get the ID token passed.
  const idToken = req.body.idToken;
  // Verify the ID token and decode its payload.
  admin
    .auth()
    .verifyIdToken(idToken)
    .then((claims) => {
      // Verify user is eligible for additional privileges.
      // &&
      // claims.email.endsWith('@admin.example.com')
      console.log('claims', claims);
      if (
        typeof claims.email !== 'undefined' &&
        typeof claims.email_verified !== 'undefined'
      ) {
        try {
          admin
            .auth()
            .setCustomUserClaims(claims.sub, {
              role: 'mod',
            })
            .then(function () {
              // Tell client to refresh token on user.
              res.end(
                JSON.stringify({
                  status: 'success',
                })
              );
            });
        } catch (error) {
          res.send(`error: ${JSON.stringify(error)}`);
        }
        // Add custom claims for additional privileges.
      } else {
        // Return nothing.
        res.end(JSON.stringify({ status: 'ineligible' }));
      }
    });
});

const port = process.env.port || 5000;
const server = app.listen(port, () => {
  console.log(`Listening at http://localhost:${port}/graphiql`);
});
server.on('error', console.error);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants