Skip to content

Instantly share code, notes, and snippets.

Created January 25, 2023 20:06
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
What would you like to do?
Knock In-app Notifications with NextAuth/AuthJS
# These values all come from the dashboard
# Replace each line break with `\n` and then wrap the whole thing in JSON. JSON.parse will properly decode all of it.
KNOCK_SIGNING_KEY='{"key": "-----BEGIN RSA PRIVATE KEY-----\n<The rest of the key goes here>\n-----END RSA PRIVATE KEY-----"}'
// This file is adapted from
import NextAuth, { NextAuthOptions } from "next-auth"
import CredentialsProvider from 'next-auth/providers/credentials'
import jwt from "jsonwebtoken";
// Here is where we extract the Knock signing key to use later.
const knockSigningKey = JSON.parse(process.env.KNOCK_SIGNING_KEY as string).key;
export const authOptions: NextAuthOptions = {
providers: [
CredentialsProvider({ // Using this provider as an example.
name: "Credentials",
credentials: {
username: { label: "Username", type: "text", placeholder: "jsmith" },
password: { label: "Password", type: "password" }
async authorize(credentials, req) {
const user = { id: "1", name: "J Smith", email: "" }
if (user) {
return user
} else {
return null
callbacks: {
async session({ session, token, user }) {
// This section is adapted from the Knock docs:
// JWT NumericDates specified in seconds:
const currentTime = Math.floor( / 1000);
// Using any because the session type does not support custom properties, but it will pass them through to the client.
(session as any).knockToken =
sub: token.sub, // token.sub is the user ID from our provider. You can incorporate the JWT callback, or draw from the user's email, although Knock discourages using email as the user's ID since emails can change but IDs are immutable.
iat: currentTime,
exp: currentTime + 60 * 60, // 1 hour from now
algorithm: "RS256",
// The user ID is passed through here so we can surface it in the component.
(session as any) = token.sub;
return session;
export default NextAuth(authOptions)

These are some excerpts adapted from the Nextauth example.

Getting started

  1. Grab your Knock Client Secret Key. Replace every line break with \n and wrap it in JSON (see example). Store this in the environment variable KNOCK_SIGNING_KEY. Be sure to not let this variable be public.
  2. Grab your Knock public key for the environment. Store it in NEXT_PUBLIC_KNOCK_PUBLIC_API_KEY.
  3. Grab the ID of the channel you want to surface in the in-app feed. Store it in NEXT_PUBLIC_KNOCK_FEED_ID
  4. Update the session callback in your nextauth code to set the knockToken
// This is from
// You will need to adapt the instructions from the Knock docs for including the feed to fit your use case.
// See
import {
} from "@knocklabs/react-notification-feed";
// Required CSS import, unless you're overriding the styling
import "@knocklabs/react-notification-feed/dist/index.css";
import { useSession } from "next-auth/react";
import { useRef, useState } from "react";
import Layout from "../components/layout"
export default function IndexPage() {
const { data: session } = useSession();
const [isVisible, setIsVisible] = useState(false);
const notifButtonRef = useRef(null);
return (
<h1>NextAuth.js Example</h1>
This is an example site to demonstrate how to use{" "}
<a href="">NextAuth.js</a> for authentication.
{/* Here is where we start integrating the Knock feed */}
{(session?.user as any)?.id && <KnockFeedProvider
apiKey={process.env.NEXT_PUBLIC_KNOCK_PUBLIC_API_KEY as string}
feedId={process.env.NEXT_PUBLIC_KNOCK_FEED_ID as string}
userId={(session?.user as any)?.id}
userToken={(session as any)?.knockToken}
onClick={(e) => setIsVisible(!isVisible)}
onClose={() => setIsVisible(false)}
</KnockFeedProvider> }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment