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

Adding Firebase to the AuthClients #593

Merged
merged 6 commits into from
May 31, 2020

Conversation

noire-munich
Copy link
Collaborator

@noire-munich noire-munich commented May 24, 2020

Pull request draft, There are a couple of todos to get it to work.

Otherwise dirtily tested in a project, seems to work properly.

Firebase Authentication

The Firebase authentication will require you to register your application to the firebase console - it's not as long as it sounds, everything is detailed in the official documentation: https://firebase.google.com/docs/web/setup

Once you are done it is time to write some code.

In web/src/index.js, make sure to have these lines:

  • in the imports
import { AuthProvider } from '@redwoodjs/auth'
import * as firebase from 'firebase/app'
import 'firebase/auth'
  • after the imports, before the main component
    (You will find the below snippet in the Firebase console, Project settings > General Parameters )
const config = {
  apiKey: '...',
  authDomain: '....firebaseapp.com',
  databaseURL: 'https://....firebaseio.com',
  projectId: '...',
  storageBucket: '....appspot.com',
  messagingSenderId: '...',
  appId: '...',
}

const firebaseClient = ((config) => {
  firebase.initializeApp(config)
  return firebase
})(config)
  • Now to your main component:
ReactDOM.render(
  <FatalErrorBoundary page={FatalErrorPage}>
    <AuthProvider client={firebaseClient} type={'firebase'}>
      <RedwoodProvider>
          <App />
      </RedwoodProvider>
    </AuthProvider>
  </FatalErrorBoundary>,
  document.getElementById('redwood-app')
)

We have setup the AuthClient for RedwoodJS, this means that we can now use the useAuth() hook from RedwoodJs. But we are not done yet, as we still need to change an important file on the API side.

If it doesn't exist, add api/src/lib/auth.ts and consider this implementation of the much needed getCurrentUser function:

import admin from 'firebase-admin'

import { db } from './db'

const config = {
  apiKey: '...',
  authDomain: '....firebaseapp.com',
  databaseURL: 'https://....firebaseio.com',
  projectId: '...',
  storageBucket: '....appspot.com',
  messagingSenderId: '...',
  appId: '...',
}

const adminApp = admin.initializeApp(config)

const getCurrentUser: (token: string) => Promise<object> = (token) =>
  adminApp
    .auth()
    .verifyIdToken(token)
    .then(({ email, uid }) =>
      db.user
        .findMany({
          first: 1,
          where: { OR: [{ email }, { uid }] },
        })
        .then(([user]) => user ?? 'User not found')
    )

export { getCurrentUser }

Now make sure that you pass this getCurrentUser to the createGraphQLHandler in api/src/functions/graphql.js:


export const handler = createGraphQLHandler({
  db,
  schema: makeMergedSchema({
    schemas,
    services: makeServices({ services }),
  }),
  getCurrentUser,
})

And you should be good to go.
In your services you will be able to fetch your current user using this import:
import { context } from '@redwoodjs/api'. It will have the type of whichever data you are sending back from the getCurrentUser function.

@thedavidprice
Copy link
Contributor

Conversation thread in forums here:
https://community.redwoodjs.com/t/adding-firebase-as-an-authclient/594

@noire-munich
Copy link
Collaborator Author

noire-munich commented May 26, 2020

Thanks a lot for your 2ç @thedavidprice ;), I'm fully migrating the conversation here - if it's ok.
Disclaimer: I also don't have xp in firebase, nor do I have much in auth in general, so all this is rather new!

@peterp I'm pinging you, I don't want to take decisions on the matter, I'm happy to offer my own 2ç ( so far makes a piggy of 4ç! ) and happy to extend my PR, but I'd need some directions to make sure what I'd propose follows RW's line and the community's interests.

Picking up where @thedavidprice lead us:

2. Identity Providers
I gather Firebase offers some Auth Providers including OAuthProvider but from what I see in the code, even though there's a documented list ( which you provided ) there's nothing special made for either provider ( no linkedin specific code for instance ).
My PR proposes to use GoogleAuthProvider instead of any of the other seven mentioned here: https://firebase.google.com/docs/reference/js/firebase.auth.AuthProvider
I followed the same logic you mention and applied the recommendation for apps should they be intended for mobile use, which is to use the signInWithRedirect method ( see https://firebase.google.com/docs/auth/web/google-signin#handle_the_sign-in_flow_with_the_firebase_sdk item 5 ). This is widely opened for debate :), but for a fast working first draft it felt appropriate.

I'd vote to offer a very rudimentary default - this one seems to work, and figure out how to make it possible for the end user to implement the complexity they want, as you suggest, since Firebase offers plenty. @peterp what would be your stand here?

3. FirebaseUI
Available UI seems to depend on which sign in method is used. signInWithRedirect will... redirect you and provide a very familiar UI to any google user. FirebaseUi will display buttons depending on which providers you have listed as supported, it requires modification of the DOM so if implemented, maybe we should extend a bit what's in the AuthClient type - or keep it to documentation use case indeed.

4: Documentation
Will do, in the PR?

5. RW Auth Generator
Ok, I'll follow the core team's lead on this :p

@peterp
Copy link
Contributor

peterp commented May 26, 2020

My PR proposes to use GoogleAuthProvider instead of any of the other seven mentioned here [...] I'd vote to offer a very rudimentary default

That sounds reasonable. In the future, I think we could add a way to "pick" the auth provider, but I guess we need to be certain that the other methods work for those providers. Picking a provider could look something like:

 login: async (provider =  "GoogleAuthProvider") => {
      const provider = new client.auth[provider]()
      return client.auth().signInWithRedirect(provider)
    },

What kind of token does this push onto the api side?

@noire-munich
Copy link
Collaborator Author

noire-munich commented May 26, 2020

@peterp agreed, it requires a thorough verification before.

The token is encoded, I decoded it in auth.js:

const getCurrentUser: (token: string) => Promise<object> = (token) =>
  adminApp
    .auth()
    .verifyIdToken(token)
    .then(({ email, uid }) =>
      db.user
        .findMany({
          first: 1,
          where: { OR: [{ email }, { uid }] },
        })
        .then(([user]) => user ?? 'User not found')
    )

I have to move it ( the verifyIdToken part, not the findMany ) to authHeaders.js but it relies on a different client app, firebase-admin, I don't know how I can make it work. Should I leave it in auth.js and emphasize it in the doc?

The token provides a user object with the following keys:

'name',
'picture',
'iss',
'aud',
'auth_time',
'user_id',
'sub',
'iat',
'exp',
'email',
'email_verified',
'firebase',
'uid',

@peterp
Copy link
Contributor

peterp commented May 26, 2020

The token is encoded, I decoded it in auth.js:

That's fine. That's the approach that we've taken with magic.link as well.

@noire-munich
Copy link
Collaborator Author

@peterp what would be missing to have it merged in a first version?

@peterp
Copy link
Contributor

peterp commented May 29, 2020

Hey @noire-munich - I'll put this into my review queue, it should be merged this weekend :)

@peterp peterp self-assigned this May 30, 2020
@peterp peterp merged commit fae8756 into redwoodjs:master May 31, 2020
@thedavidprice thedavidprice added this to the next release milestone May 31, 2020
@noire-munich
Copy link
Collaborator Author

Coverage

The PR is very straightforward, it offers only a sign up with redirect feature, it lets Google take on the entire process ( display & events ).

It doesn't cover:

  • Allowing to change the provider - GoogleAuth is forced by default.
  • Allowing to change the sign up method - signUpWithRedirect is forced, firebase offers a couple more.
  • Support for FirebaseUi or any sort of ui packed in RW
  • Testing

@ghost
Copy link

ghost commented Jun 14, 2020

Does this allow signup with email/password or only the googleAuth?

@ghost
Copy link

ghost commented Jun 14, 2020

@redwoodjs/auth also can't be found.

import { AuthProvider } from '@redwoodjs/auth'

./src/index.js
Module not found: Can't resolve '@redwoodjs/auth' in '/Users/adam/Development/redwood/notsgram/web/src'

@peterp
Copy link
Contributor

peterp commented Jun 14, 2020

@AWey95 It doesn't at the moment, but you could use Netlify identity for that.

Check out this guide for how to get started with authentication: https://redwoodjs.com/docs/authentication

@ghost
Copy link

ghost commented Jun 15, 2020

@AWey95 It doesn't at the moment, but you could use Netlify identity for that.

Check out this guide for how to get started with authentication: https://redwoodjs.com/docs/authentication

Would this force me to use their own premade UI or can I stick with the design I already have? I would rather not have any popups or email links to get this working.

@peterp
Copy link
Contributor

peterp commented Jun 15, 2020

Hey @AWey95, so you're already using Firebase? And you want to use your own UI to instead of the pop-up?

@ghost
Copy link

ghost commented Jun 27, 2020

Hey @AWey95, so you're already using Firebase? And you want to use your own UI to instead of the pop-up?

That's correct. I would rather not use a pop-up so I can keep my design consistent throughout. The pop-up is fine for google/github auth but if someone is authenticating with email/password I want them to use my form. I haven't used Firebase with redwoodjs yet. I have used their auth system before though.

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

Successfully merging this pull request may close these issues.

None yet

3 participants