Skip to content

descope-sample-apps/nextjs-hackathon-template

Repository files navigation

Next.js Hackathon Template

🪐 The Hackathon template comes with the following full-stack features:

  • Descope NextAuth authentication 🔐
  • Protected pages & API routes with NextAuth.
  • The latest Next.js app router, server & client components.
  • Fully customizable Home screen which features an About, Speakers, Sponsors, and FAQ section.
  • A dedicated Team page to showcase all contributors.
  • A Dashboard page for Hackers to complete onboarding forms, acceptance status, and hackathon announcements.
  • Airtable backend for hackers to signup and view hackathon details.
  • Fully responsive UI (mobile, tablet, computer).

✨ Made with...

⚙️ Setup: Local Testing

  1. In the root directory of the project, copy the .env.example to .env by running cp .env.example .env and include the following:
NEXTAUTH_SECRET="YOUR_NEXTAUTH_SECRET"
NEXTAUTH_URL="WHERE SERVER IS HOSTED (e.g. http://localhost:3000)"

DESCOPE_PROJECT_ID="YOUR_DESCOPE_PROJECT_ID"
DESCOPE_ACCESS_KEY="YOUR_DESCOPE_ACCESS_KEY"
NEXT_PRIVATE_SECRET_TOKEN="YOUR_SECRET_TOKEN"
  • DESCOPE_PROJECT_ID - can be found in your Descope's account under the Project page
  • DESCOPE_ACCESS_KEY - can be generated in your Descope's account under the Access Keys page
  • NEXTAUTH_SECRET and NEXT_PRIVATE_SECRET_TOKEN can be generated by the following command in your terminal (do not use the same generated value for both):
$ openssl rand -base64 32

NOTE: The NEXT_PRIVATE_SECRET_TOKEN is used to authenticate the request in the API. It is passed as a parameter in the fetch URL.

  1. Setup SSO
  • To enable SSO and add Descope as an Identity Provider (IdP), we need to add our flow hosting URL:
https://auth.descope.io/<YOUR_DESCOPE_PROJECT_ID>
  • Navigate to Descope Project --> Authentication methods --> Identity Provider:

  1. Installation
  • npm install
  • npm run dev
  • Open http://localhost:3000 in your browser

🔑 Descope

To use Descope, we can implement a custom provider.

Out NextAuth options can be found in /app/_utils/options.ts.

In our authOptions we have our custom Descope provider we have attributes such as your clientID (Descope project id), clientSecret (Descope access key), and wellKnown set to Descope's OpenID Connect configuration which contains our authorization endpoints and authentication data.

import { NextAuthOptions } from "next-auth"


export const authOptions: NextAuthOptions = {
  providers: [
    {
      id: "descope",
      name: "Descope",
      type: "oauth",
      wellKnown: `https://api.descope.com/${process.env.DESCOPE_PROJECT_ID}/.well-known/openid-configuration`,
      authorization: {
        params: { scope: "openid email profile descope.custom_claims" },
      },
      idToken: true,
      clientId: process.env.DESCOPE_PROJECT_ID,
      clientSecret: process.env.DESCOPE_ACCESS_KEY,
      checks: ["pkce", "state"],
      profile(profile, tokens) {
        return {
          id: profile.sub,
          name: profile.name,
          email: profile.email,
          image: profile.picture,
          idToken: tokens.id_token,
          ...tokens,
        };
      },
    },
  ],
  callbacks: {
    async jwt({ token, account }) {
      if (account?.id_token) {
        token.idToken = account.id_token;
      }
      return token;
    },
    async session({ session, token, user }) {
      // @ts-ignore
      session.idToken = token.idToken;
      return session;
    },
  },
}

Note: The purpose of the callbacks at the end, are to be able to fetch the id_token and include it in the NextAuth Session object. You will be able to access custom_claims also through this id_token using getSession() on the client side.

Then in our /app/api/auth/[...nextauth]/route.ts we pass our authOptions and intialize NextAuth.

import NextAuth from "next-auth/next";
import { authOptions } from "../../../_utils/options";


const handler = NextAuth(authOptions)


export { handler as GET, handler as POST }

👾 Template Data

The template data can be found in the ./app/_template_data

All the template data can be customized and found in the following files.

To see our template data in action make your way to app/page.tsx.
In the page.tsx we import the different template data and the components from our _components folder. We pass in our template data into these components as props that then render the data!

📦 Airtable Setup

NOTE: This step is Optional!

To learn more about creating a form and setting up Airtable as a database go to Airtable.md!

🚀 Deploy

Deploy with Vercel