In the last part, we initialised our application. In this part, we'll look at authentication using Firebase.
Make sure you've gone through the first part before continuing!
The github code for this project is available here
We've already setup authentication on firebase, so let's do the setup on our app!
Email and password authentication
We'll mostly be focusing on one file, src/components/Auth.svelte
.
Register
Let's first add register functionality! We'll only need to update the register()
function.
<!-- src/components/Auth.svelte -->
<script lang="ts">
// ...
import {auth} from "../services/firebase";
import {createEventDispatcher} from "svelte";
const d = createEventDispatcher();
// ...
function register() {
// if you're using js, remove the "as HTMLInputElement" for each of them
const email = (document.getElementById("r-email") as HTMLInputElement).value
const password = (document.getElementById("r-password") as HTMLInputElement).value
const cpassword = (document.getElementById("r-cpassword") as HTMLInputElement).value
// form validation
if (!email || !password || !cpassword) {
err = "Fill out all fields!"
return;
}
if (password !== cpassword) {
err = "Passwords don't match!"
return;
}
err = "";
// creating the user
auth.createUserWithEmailAndPassword(email, password).then(() => {d("done"); d("auth")}).catch(e => {
err = `(${e.code}) ${e.message}`
})
}
// ...
</script>
<!-- ... -->
Time to test it out! Run your app and open http://localhost:3000. Now, you can register an account and you should see that account appear in the firebase auth page on the firebase console
Login
Now for login! Just like register, we only have to edit the login()
function.
<!-- src/components/Auth.svelte -->
<script lang="ts">
// ...
function login() {
// again, remove "as HTMLInputElement" if using js
const email = (document.getElementById("l-email") as HTMLInputElement).value
const password = (document.getElementById("l-password") as HTMLInputElement).value
// basic form validation
if (!email || !password) {
err = "Fill out all fields!"
return;
}
err = "";
// sign in using firebase
auth.signInWithEmailAndPassword(email, password).then(() => {d("done"); d("auth")}).catch(e => {
err = `(${e.code}) ${e.message}`
})
}
// ...
</script>
<!-- ... -->
Now, once we test that, you should hopefully see a green checkmark! Yay! We can now login and register with an email and a password.
Google signin
Now, let's address the easier one, signing in with Google. Firebase makes it as easy as one method!
<!-- src/components/Auth.svelte -->
<script lang="ts">
// ...
function google() {
auth.signInWithPopup(googleAuth).then(() => {
d("auth");
d("done");
}).catch(e => {
err = `(${e.code}) ${e.message}`
})
}
// ...
</script>
<!-- ... -->
Now, when you click the signin with Google button, it should allow you to sign in! Hurrah
Logout
Let's also add functionality to the logout button. Again, we only need to change the logout()
method, and again, firebase makes it super easy!
<!-- src/components/Auth.svelte -->
<script lang="ts">
// ...
function logout() {
if (auth.currentUser) {
auth.signOut().then(() => {d("done"); d("logout")}).catch(e => {
throw new Error(e)
});
}
}
// ...
</script>
<!-- ... -->
Now you may wonder why I'm dispatching events left and right everywhere. This is because we can use this Auth component in web pages and get to know when the person logs in. One such implementation is the index.svelte
route:
<!-- src/routes/index.svelte -->
<script lang="ts">
import Auth from "../components/Auth.svelte";
</script>
<h1 class="w3-jumbo w3-center">Serverless Chat</h1>
<p class="w3-large w3-center">Please log in</p>
<Auth on:auth={() => window.location.href = "/chat"} />
I also created an auth.svelte
route, so that users can directly login, but, this time, we can specify which action we want to do, instead of register at first, and also where to go next after we've logged in.
<!-- src/routes/auth.svelte -->
<script lang="ts">
import Auth from "../components/Auth.svelte";
export let qs;
qs.action = qs.action || "register"
if (!["login", "register"].includes(qs.action)) qs.action = "register"
</script>
<h1 class="w3-center w3-jumbo">Authenticate to Serverless Chat</h1>
<Auth authMode={qs.action} on:auth={() => window.location.href=qs.next || "/"} />
Let's add a route to this page in App.svelte
. While we're there, let's also add a 404 route.
<!-- src/App.svelte -->
<script lang="ts">
import router from "page";
import Auth from "./routes/auth.svelte";
import Index from "./routes/index.svelte";
import NotFound from "./routes/notfound.svelte";
import { queryString } from "./services/util";
let page;
let params = {};
let qs = {};
router("/", () => page = Index)
router("/404/:msg", (ctx: {params: {}, querystring: string}, next) => {
params = ctx.params;
next();
}, () => page = NotFound)
router("/auth", (ctx, next) => {
qs = queryString(ctx.querystring)
next();
}, () => page = Auth)
router("/login", () => router.redirect("/auth"))
router("/register", () => router.redirect("/auth"))
router("/*", () => page = NotFound)
router.start();
</script>
<svelte:component this={page} {params} {qs} />
src/services/util.ts
:
<!-- src/services/util.ts -->
export function queryString(unparsed: string): {} {
const separated = unparsed.replace("?", "").split("&");
if (!separated) return {};
const query = {};
for (let item of separated) {
const x = item.split("=");
query[x[0]] = x[1];
}
return query;
}
src/routes/notfound.svelte
<!-- src/routes/notfound.svelte -->
<script lang="ts">
export let params = {msg: ""}
</script>
<h1 class="w3-jumbo w3-center">404</h1>
<p class="w3-large w3-center">Not found</p>
<p class="w3-center w3-text-gray">{params.msg || "The page you were looking for was not found."}<br> <a href="/">Home</a></p>
And there! That wraps up the authentication part! Stay tuned for the next part, which is the chat functionality itself! The link to the 3rd part is here
Top comments (2)
Did you catch the d('done') event? I search on:done in your repo and found no result..
Nope, I don't think I used that code anywhere, but I think I planned to so so and forgot about it. Oops :P