Skip to content

Instantly share code, notes, and snippets.

@gautamsi
Created November 9, 2021 05:43
Show Gist options
  • Save gautamsi/d89cf29a5ea2d4c3eb0e19eb248a8d9c to your computer and use it in GitHub Desktop.
Save gautamsi/d89cf29a5ea2d4c3eb0e19eb248a8d9c to your computer and use it in GitHub Desktop.
Firebase Auth with Keystone
import { KeystoneContext } from '@keystone-next/keystone/types';
import admin from 'firebase-admin';
const firebase = admin.initializeApp();
export const authMutations = `
authenticateWithFirebase(token: String!): User
signupWithFirebase(
token: String!
name: String!
email: String
password: String!
): User
verifyEmailAddress(token: String!): User
verifyMobile(phone: String!): UserAlreadyExist
`;
export const authTypes = `
type UserAlreadyExist {
success: Boolean!
}
`;
export async function authenticateWithFirebase(
root: any,
{ token }: { token: string },
context: KeystoneContext
) {
const sudo = context.sudo();
const firebaseToken = await firebase.auth()?.verifyIdToken(token);
const { uid, phone_number: phone } = firebaseToken;
const firebaseUser = await sudo.lists.User.findMany({
where: {
firebaseId: { equals: uid },
phone: { equals: phone },
},
});
if (!firebaseUser.length) {
throw new Error('USER_NOT_FOUND');
}
const item = firebaseUser[0];
const newToken = await context?.startSession?.({
itemId: item?.id,
listKey: 'User',
});
if (newToken) {
return await sudo.db.lists.User.findOne({ where: { id: item.id } });
}
return null;
}
export async function signupWithFirebase(
root: any,
{
token,
name,
email,
password,
}: { token: string; name: string; email: string; password: string },
context: KeystoneContext
) {
try {
const firebaseToken = await firebase.auth().verifyIdToken(token);
const sudo = context.sudo();
const { uid, phone_number: phone } = firebaseToken;
const firebaseUser = await sudo.lists.User.findMany({
where: {
firebaseId: { equals: uid },
phone: { equals: phone },
},
});
if (firebaseUser.length) {
throw new Error('USER_ALREADY_EXIST');
}
const newUser = await sudo.lists.User.createOne({
data: {
name,
phone: phone,
firebaseId: uid,
email,
password,
},
});
const item = newUser;
const currentUser = await context?.startSession?.({
itemId: item?.id,
listKey: 'User',
});
if (currentUser) {
return await sudo.db.lists.User.findOne({ where: { id: item.id } });
}
return null;
} catch (error) {
throw new Error('Error creating User.');
}
}
export async function verifyEmailAddress(
root: any,
{ token }: { token: string },
context: KeystoneContext
) {
const user = context?.session?.data;
if (!user?.id) {
return null;
}
try {
const firebaseToken = await firebase.auth().verifyIdToken(token);
const { email_verified } = firebaseToken;
const sudo = context.sudo();
const registeredUser = await sudo.lists.User.updateOne({
where: { id: user.id },
data: {
isVerifiedEmail: email_verified,
},
query: 'id',
});
return { id: registeredUser.id };
} catch (error) {
console.log('error', error);
return null;
}
}
export async function verifyMobile(
root: any,
{ phone }: { phone: string },
context: KeystoneContext
) {
const sudo = context.sudo();
const isValid = await sudo.lists.User.findOne({
where: { phone },
query: 'id',
});
return { success: isValid?.id ? true : false };
}
import { graphQLSchemaExtension } from '@keystone-next/keystone';
import {
authenticateWithFirebase,
authMutations,
authTypes,
signupWithFirebase,
verifyEmailAddress,
verifyMobile,
} from './auth';
const typeDefs = String.raw`
${authTypes}
type Mutation {
${authMutations}
}
`;
export const extendGraphqlSchema = graphQLSchemaExtension({
typeDefs,
resolvers: {
Mutation: {
authenticateWithFirebase,
signupWithFirebase,
verifyEmailAddress,
verifyMobile,
},
},
});
@gautamsi
Copy link
Author

gautamsi commented Nov 9, 2021

import extendGraphqlSchema to add to keystone config.

@dragosstancu
Copy link

Hi,

Thank you, Sir!

That looks very exciting!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment