├── .gitignore
├── Dockerfile
├── Dockerfile-prod
├── README.md
├── package.json
├── public
├── favicon.ico
└── index.html
└── src
├── App.test.js
├── components
├── Home.js
├── Login.js
├── Register.js
├── index.js
└── protected
│ └── Dashboard.js
├── config
└── constants.js
├── helpers
└── auth.js
├── index.css
└── index.js
/.gitignore:
--------------------------------------------------------------------------------
1 | # See http://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | node_modules
5 |
6 | # testing
7 | coverage
8 |
9 | # production
10 | build
11 |
12 | # misc
13 | .DS_Store
14 | .env
15 | npm-debug.log
16 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM node:8-alpine as builder
2 |
3 | WORKDIR /code/
4 |
5 | EXPOSE 3000
6 |
7 | COPY . .
8 |
9 | RUN npm install
10 |
11 | ENTRYPOINT npm run start
12 |
--------------------------------------------------------------------------------
/Dockerfile-prod:
--------------------------------------------------------------------------------
1 | FROM node:8-alpine as builder
2 |
3 | WORKDIR /code/
4 |
5 | EXPOSE 3000
6 |
7 | COPY . .
8 |
9 | RUN npm install --unsafe-perm
10 |
11 | RUN npm run build
12 |
13 |
14 | FROM nginx
15 |
16 | WORKDIR /usr/share/nginx/html
17 |
18 | COPY --from=builder /code/build .
19 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Auth with React Router V4 and Firebase V3
2 | This is an example repo for authenticating with Firebase and React Router.
3 |
4 | For more info, visit [Protected routes and authentication with React Router v4](https://tylermcginnis.com/react-router-protected-routes-authentication/)
5 |
6 | *Using React 15.4.0, React Router 4, and Firebase 3.6.1*
7 |
8 | #### Features:
9 | * Protected Routes with React Router
10 | * Register new users with Firebase
11 | * Add new users to ```/users``` in your Firebase database
12 | * Login/Logout Functionality
13 | * Simple Boostrap UI
14 |
15 | #### Instructions:
16 | * Swap out the firebase config in ```config/constants``` with your own
17 | * ```npm install```
18 | * ```npm start```
19 | * Visit ```localhost:3000```
20 |
21 | #### Try it out in a [Docker](https://www.docker.com/) container:
22 | * Run a container running the prod version: `docker run -p 8080:80 -d allthethings/react-router-firebase-auth`
23 | * **Or** build a dev version, locally: `docker build -t react-router-firebase-auth .`
24 | * Then run the image (listens for changes to src): `docker run -v "$(pwd)/src:/code/src" -p 3000:3000 -d --name react-router-firebase-auth react-router-firebase-auth`
25 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-router-firebase-auth",
3 | "version": "0.1.0",
4 | "private": true,
5 | "devDependencies": {
6 | "react-scripts": "0.9.5"
7 | },
8 | "dependencies": {
9 | "bootstrap": "^3.3.7",
10 | "firebase": "^3.6.1",
11 | "react": "^15.4.0",
12 | "react-dom": "^15.4.0",
13 | "react-router-dom": "^4.0.0-beta.8"
14 | },
15 | "scripts": {
16 | "start": "react-scripts start",
17 | "build": "react-scripts build",
18 | "test": "react-scripts test --env=jsdom",
19 | "eject": "react-scripts eject"
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tylermcginnis/react-router-firebase-auth/c999cd9a5c80236aefefaf3a87b2f3c8194a30f0/public/favicon.ico
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
16 | React App
17 |
18 |
19 |
20 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/src/App.test.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import App from './components';
4 |
5 | it('renders without crashing', () => {
6 | const div = document.createElement('div');
7 | ReactDOM.render(, div);
8 | });
9 |
--------------------------------------------------------------------------------
/src/components/Home.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 |
3 | export default class Home extends Component {
4 | render () {
5 | return (
6 |
7 | Home. Not Protected. Anyone can see this.
8 |
9 | )
10 | }
11 | }
--------------------------------------------------------------------------------
/src/components/Login.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import { login, resetPassword } from '../helpers/auth'
3 |
4 | function setErrorMsg(error) {
5 | return {
6 | loginMessage: error
7 | }
8 | }
9 |
10 | export default class Login extends Component {
11 | state = { loginMessage: null }
12 | handleSubmit = (e) => {
13 | e.preventDefault()
14 | login(this.email.value, this.pw.value)
15 | .catch((error) => {
16 | this.setState(setErrorMsg('Invalid username/password.'))
17 | })
18 | }
19 | resetPassword = () => {
20 | resetPassword(this.email.value)
21 | .then(() => this.setState(setErrorMsg(`Password reset email sent to ${this.email.value}.`)))
22 | .catch((error) => this.setState(setErrorMsg(`Email address not found.`)))
23 | }
24 | render () {
25 | return (
26 |
48 | )
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/components/Register.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import { auth } from '../helpers/auth'
3 |
4 | function setErrorMsg(error) {
5 | return {
6 | registerError: error.message
7 | }
8 | }
9 |
10 | export default class Register extends Component {
11 | state = { registerError: null }
12 | handleSubmit = (e) => {
13 | e.preventDefault()
14 | auth(this.email.value, this.pw.value)
15 | .catch(e => this.setState(setErrorMsg(e)))
16 | }
17 | render () {
18 | return (
19 |
41 | )
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/components/index.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 | import 'bootstrap/dist/css/bootstrap.css'
3 | import { Route, BrowserRouter, Link, Redirect, Switch } from 'react-router-dom'
4 | import Login from './Login'
5 | import Register from './Register'
6 | import Home from './Home'
7 | import Dashboard from './protected/Dashboard'
8 | import { logout } from '../helpers/auth'
9 | import { firebaseAuth } from '../config/constants'
10 |
11 | function PrivateRoute ({component: Component, authed, ...rest}) {
12 | return (
13 | authed === true
16 | ?
17 | : }
18 | />
19 | )
20 | }
21 |
22 | function PublicRoute ({component: Component, authed, ...rest}) {
23 | return (
24 | authed === false
27 | ?
28 | : }
29 | />
30 | )
31 | }
32 |
33 | export default class App extends Component {
34 | state = {
35 | authed: false,
36 | loading: true,
37 | }
38 | componentDidMount () {
39 | this.removeListener = firebaseAuth().onAuthStateChanged((user) => {
40 | if (user) {
41 | this.setState({
42 | authed: true,
43 | loading: false,
44 | })
45 | } else {
46 | this.setState({
47 | authed: false,
48 | loading: false
49 | })
50 | }
51 | })
52 | }
53 | componentWillUnmount () {
54 | this.removeListener()
55 | }
56 | render() {
57 | return this.state.loading === true ? Loading
: (
58 |
59 |
60 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 | No Match
} />
96 |
97 |
98 |
99 |
100 |
101 | );
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/src/components/protected/Dashboard.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react'
2 |
3 | export default class Dashboard extends Component {
4 | render () {
5 | return (
6 |
7 | Dashboard. This is a protected route. You can only see this if you're authed.
8 |
9 | )
10 | }
11 | }
--------------------------------------------------------------------------------
/src/config/constants.js:
--------------------------------------------------------------------------------
1 | import firebase from 'firebase'
2 |
3 | const config = {
4 | apiKey: "AIzaSyDHL6JFTyBcaV60WpE4yXfeO0aZbzA9Xbk",
5 | authDomain: "practice-auth.firebaseapp.com",
6 | databaseURL: "https://practice-auth.firebaseio.com",
7 | }
8 |
9 | firebase.initializeApp(config)
10 |
11 | export const ref = firebase.database().ref()
12 | export const firebaseAuth = firebase.auth
--------------------------------------------------------------------------------
/src/helpers/auth.js:
--------------------------------------------------------------------------------
1 | import { ref, firebaseAuth } from '../config/constants'
2 |
3 | export function auth (email, pw) {
4 | return firebaseAuth().createUserWithEmailAndPassword(email, pw)
5 | .then(saveUser)
6 | }
7 |
8 | export function logout () {
9 | return firebaseAuth().signOut()
10 | }
11 |
12 | export function login (email, pw) {
13 | return firebaseAuth().signInWithEmailAndPassword(email, pw)
14 | }
15 |
16 | export function resetPassword (email) {
17 | return firebaseAuth().sendPasswordResetEmail(email)
18 | }
19 |
20 | export function saveUser (user) {
21 | return ref.child(`users/${user.uid}/info`)
22 | .set({
23 | email: user.email,
24 | uid: user.uid
25 | })
26 | .then(() => user)
27 | }
28 |
--------------------------------------------------------------------------------
/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: sans-serif;
5 | }
6 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import App from './components';
4 | import './index.css';
5 |
6 | ReactDOM.render(
7 | ,
8 | document.getElementById('root')
9 | );
10 |
--------------------------------------------------------------------------------