Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions examples/firebase-auth-firestore/.env.example
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Set the SERVICE_ACCOUNT value to be the minified contents of Admin SDK JSON file for your Firebase project
SERVICE_ACCOUNT={"type":"service_account","project_id": "your-project-id","private_key_id": "123123123123asdf123123","private_key": "-----BEGIN PRIVATE KEY-----\nLongStringOfAlphanumericCharactersWillBeHere=\n-----END PRIVATE KEY-----\n","client_email": "firebase-adminsdk-123abc@your-project--id.iam.gserviceaccount.com","client_id": "123455678901234567890","auth_uri": "https://accounts.google.com/o/oauth2/auth","token_uri": "https://oauth2.googleapis.com/token","auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs","client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/firebase-adminsdk-qh94c%40your-project-id.iam.gserviceaccount.com"}

# Set the CLIENT_CONFIG value to be the JSON stringified value of the client credentials for your Firebase project
CLIENT_CONFIG={"apiKey":"abcdefg_1234567890","authDomain":"your-project-id.firebaseapp.com","projectId":"your-project-id","storageBucket":"your-project-id.appspot.com","messagingSenderId":"1234567890","appId":"1:1234567890:web:01234567890abc"}
# Set the API_KEY value to the Web API Key, which can be obtained on the project settings page in your Firebase admin console
API_KEY="abcdefg_1234567890"
4 changes: 2 additions & 2 deletions examples/firebase-auth-firestore/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ To run it, you need to either:
1. [Create a Firebase Project](https://console.firebase.google.com)
2. Enable Auth (with email) and Firestore
3. Add a Web App
4. Get the [admin-sdk](https://firebase.google.com/docs/admin/setup#initialize-sdk) and [client-sdk credentials](https://firebase.google.com/docs/web/learn-more#config-object)
5. Save them to SERVICE_ACCOUNT and CLIENT_CONFIG in the `.env`-file
4. Get the [admin-sdk](https://firebase.google.com/docs/admin/setup#initialize-sdk) and [Web API Key](https://firebase.google.com/docs/reference/rest/auth)
5. Save them to SERVICE_ACCOUNT and API_KEY in the `.env`-file

### 2. Use the Firebase emulators

Expand Down
8 changes: 1 addition & 7 deletions examples/firebase-auth-firestore/app/server/auth.server.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import type { Session } from "@remix-run/node";
import { redirect } from "@remix-run/node";
import { signInWithEmailAndPassword } from "firebase/auth";
import type { UserRecord } from "firebase-admin/auth";

import { destroySession, getSession } from "~/sessions";
Expand Down Expand Up @@ -29,12 +28,7 @@ export const requireAuth = async (request: Request): Promise<UserRecord> => {
};

export const signIn = async (email: string, password: string) => {
const { user } = await signInWithEmailAndPassword(
auth.client,
email,
password
);
const idToken = await user.getIdToken();
const { idToken } = await auth.signInWithPassword(email, password);
const expiresIn = 1000 * 60 * 60 * 24 * 7; // 1 week
const sessionCookie = await auth.server.createSessionCookie(idToken, {
expiresIn,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
interface RestError {
error: {
code: number;
message: string;
errors: any[];
};
}

export const isError = (input: unknown): input is RestError =>
!!input && typeof input === "object" && "error" in input;

// https://firebase.google.com/docs/reference/rest/auth#section-sign-in-email-password
interface SignInWithPasswordResponse extends Response {
json(): Promise<
| RestError
| {
/**
* A Firebase Auth ID token for the authenticated user.
*/
idToken: string;
/**
* The email for the authenticated user.
*/
email: string;
/**
* A Firebase Auth refresh token for the authenticated user.
*/
refreshToken: string;
/**
* The number of seconds in which the ID token expires.
*/
expiresIn: string;
/**
* The uid of the authenticated user.
*/
localId: string;
/**
* Whether the email is for an existing account.
*/
registered: boolean;
}
>;
}

export const signInWithPassword = async (
body: {
email: string;
password: string;
returnSecureToken: true;
},
restConfig: {
apiKey: string;
domain: string;
}
) => {
const response: SignInWithPasswordResponse = await fetch(
`${restConfig!.domain}/v1/accounts:signInWithPassword?key=${
restConfig!.apiKey
}`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(body),
}
);
return response.json();
};
63 changes: 35 additions & 28 deletions examples/firebase-auth-firestore/app/server/firebase.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,39 +3,29 @@ import {
initializeApp as initializeServerApp,
cert as serverCert,
} from "firebase-admin/app";
import {
getApps as getClientApps,
initializeApp as initializeClientApp,
} from "firebase/app";
import { getAuth as getServerAuth } from "firebase-admin/auth";
import { getAuth as getClientAuth, connectAuthEmulator } from "firebase/auth";

if (getClientApps().length === 0) {
let config,
useEmulator = false;
if (process.env.NODE_ENV === "development" && !process.env.CLIENT_CONFIG) {
console.warn(
"Missing CLIENT_CONFIG environment variable, using local emulator"
);
config = {
import * as firebaseRest from "./firebase-rest.server";

const getRestConfig = (): {
apiKey: string;
domain: string;
} => {
if (process.env.NODE_ENV === "development" && !process.env.API_KEY) {
return {
apiKey: "fake-api-key",
projectId: "remix-emulator",
domain: "http://localhost:9099/identitytoolkit.googleapis.com",
};
useEmulator = true;
} else if (!process.env.CLIENT_CONFIG) {
throw new Error("Missing CLIENT_CONFIG environment variable, ");
} else if (!process.env.API_KEY) {
throw new Error("Missing API_KEY environment variable");
} else {
try {
config = JSON.parse(process.env.CLIENT_CONFIG);
} catch {
throw Error("Invalid CLIENT_CONFIG environment variable");
}
}
initializeClientApp(config);
if (useEmulator) {
connectAuthEmulator(getClientAuth(), "http://localhost:9099");
return {
apiKey: process.env.API_KEY,
domain: "https://identitytoolkit.googleapis.com",
};
}
}
};
const restConfig = getRestConfig();

if (getServerApps().length === 0) {
let config;
Expand Down Expand Up @@ -64,7 +54,24 @@ if (getServerApps().length === 0) {
initializeServerApp(config);
}

const signInWithPassword = async (email: string, password: string) => {
const signInResponse = await firebaseRest.signInWithPassword(
{
email,
password,
returnSecureToken: true,
},
restConfig
);

if (firebaseRest.isError(signInResponse)) {
throw new Error(signInResponse.error.message);
}

return signInResponse;
};

export const auth = {
server: getServerAuth(),
client: getClientAuth(),
signInWithPassword,
};
1 change: 0 additions & 1 deletion examples/firebase-auth-firestore/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
"@remix-run/node": "1.5.1",
"@remix-run/react": "1.5.1",
"@remix-run/serve": "1.5.1",
"firebase": "^9.6.10",
"firebase-admin": "^10.0.2",
"react": "^17.0.2",
"react-dom": "^17.0.2"
Expand Down