Chatter

A web chat application using Pusher Channels.

August 31, 2023 · 2y ago

View on GitHub

What is Chatter?

Chatter is a simple chat application for the browser. You can sign in using Google or GitHub and start a private message session with any other user. It is built using the Next.js 13 App Router and Pusher Channels.

Walkthrough

All routes except from the root are protected by middleware which checks whether the user is signed in or not. If the user is not authenticated, they are redirected to the sign-in page.

Chatter's sign-in page. There is a section containing a disabled credential sign-in form and below that are two buttons to sign in using Google or GitHub.

Authentication is handled by NextAuth (now Auth.js) and allows the user to sign in using two OAuth providers: Google, and GitHub. Chatter was originally meant to use credential sign-in, but this was not possible. More Below.

When a new user signs in, before they can proceed they must choose a username. Usernames are used by users to start chat sessions with one another.

A signed-in user is prompted to choose a username before they can continue.

When a new user chooses a username, or if they already have a username, they are redirected to the /m/ route. Here, users can start chats with anyone they know the username of. Clicking the Start New Chat button in the sidebar opens up a modal that asks for a username. If the username exists a chat session will be created.

A dialog window is open asking the user who they would like to start a chat with. There is a username field with an error stating 'Username is a required field'.

The user automatically is redirected to /m/[chatId] when a new chat is created and they can start sending messages. Message fetching works like this:

  1. User requests /m/[chatId].
  2. /m/[chatId]/page.tsx is a React Server Component, so the messages are fetched by the server.
    • A 404 error is shown if the chat does not exist.
  3. Messages get sent to a ChatBox component which is a client component.
  4. React useEffect subscribes to the Pusher channel on mount.
  5. Messages are fetched by the client using SWR.
  6. When a message is sent by the user, optimistic updates are used for instant feedback.
  7. When a message is received by Pusher, the SWR cache is mutated with the new message.
  8. Unsubscribe from the channel when the user switches routes.
A browser window shows two people conversing back and forth. On the left-hand side of the window is a sidebar containing a list of people the current user has chatted with.

Improvements

There are a few ways that I could improve this project. The first would be to limit the amount of information exposed to the user. Currently, when a chat message is sent, the message object contains the user's email address which is a private piece of information that shouldn't be shared.

Second, I should decide whether to fully implement credentials sign-in or just remove it. Before implementing NextAuth, I built the UI that would allow a user to register and sign in using a username and password. While NextAuth supports this, their support is limited in that the user will not be persisted in a database and JSON Web Tokens would have to be used instead of a session token. If I were to implement credential sign-in, it would mean a lot of extra work when OAuth sign-in works just fine, and I would also become responsible for keeping user passwords safe and secure.

What I Learned

  • NextJS App Router, including React Server Components and the metadata API.
  • How to set up and use NextAuth with multiple providers for user authentication, and its drawbacks.
  • Publish/Subscribe messaging via Pusher Channels.
  • Optimistic updates and cache mutation using SWR.