Check out our Hellō Next.js Sample (opens in a new tab) where you will be logging in with Hellō (opens in a new tab) in less than a minute.

Follow the Next.js Quickstart directions to add Hellō to your application in minutes.


Following are the steps required to setup this package:

1. Package Installation

npm i @hellocoop/nextjs

Hellō Quickstart will perform steps 2 - 5 for you

npx @hellocoop/quickstart@latest --nextjs


The environment variable HELLO_COOKIE_SECRET must be set to 64 char (32 byte) random hex string is required to encrypt cookies used by this package. This can be in .env.local for local development.

You can generate new values with:

node -e"console.log(crypto.randomBytes(32).toString('hex'))"

Remember to set a unique HELLO_COOKIE_SECRET in each of your deployed environments.

See Environment Vars for additional values that can be set.

The .env.local file should not be checked into your repository, and should be in your .gitignore file.

3. client_id

If not using Hellō Quickstart, you will need to create an application at the Hellō Developer Console (opens in a new tab) and get a client_id.

4. hello.config.js

The convention is to create a hello.config.js file in the root of your project for configuration. This file is imported into the hellocoop.js file and passed to the pageAuth() function for configuration. Below is a basic configuration file. See for additional configuration.

const config = {
    client_id: 'your-client_id-here'
module.exports = config

This file should be checked into your repository.

See hello.config.js for additional configuration.

5. API Route

The default route is /api/hellocoop, which should not conflict with any existing route. There is one endpoint for all functionality. Query parameters (login,logout,auth) are used for routing within the package. With configuration at the project root in hello.config.js, the API route is handled by:

import config from '../../hello.config'
import { pageAuth } from '@hellocoop/nextjs'
export default pageAuth(config)

6. Image Component Config

To use the Image Component (opens in a new tab) to display profile pictures add the Hellō and Gravatar domains to the images section of your next.config.js file:

const nextConfig = {
    images: {
      domains: [

7. Hellō Button Stylesheet

To provide the styling for Hellō buttons, add the below code to the <Head> section of your _document.tsx or _document.jsx file in the pages directory:

pages/_document.tsx or pages/_document.jsx
import { Html, Head, Main, NextScript } from 'next/document'
export default function Document() {
  return (
            <link rel="stylesheet" href=""/>

See Next.js Custom Document (opens in a new tab) for details.

To ensure the button styles are available, client-side rendered buttons check if the stylesheet has been included in the document head, and if not the stylesheet is injected. Injecting into the head is not recommended (opens in a new tab) and creates a button rendering glitch.

Here is a summary of setup:

├─ .env.local           2. HELLO_COOKIE_SECRET
├─ hello.config.js      3. client_id
├─ next.config.js       6. Image Component Config
└─ pages/
  ├─ _document.jsx      7. Hellō Button Stylesheet
  └─ api/  
    └─ hellocoop.js     5. API Route 


The following buttons are available:

import {
} from '@hellocoop/nextjs/react'

Note they are in @hellocoop/nextjs/react

See the SDK Reference | React for details.


The following React components are available:

import {
} from '@hellocoop/nextjs/react'

Note they are in @hellocoop/nextjs/react

See the SDK Reference | React for details.

Client APIs


import { useAuth } from '@hellocoop/nextjs'
const {
    isLoading,      // useSWR response, true if still loading call to 
    auth: undefined | {
        isLoggedIn, // always returned
        iat,        // returned if isLoggedIn == true
        sub,        // use as user identifier - returned if isLoggedIn == true
        // additional claims - following are defaults
} = useAuth()


import { logOut, logOutRoute } from '@hellocoop/nextjs'

logOut() - function to logout user, loads logOutRoute

logOutRoute - provides route to logout

Server APIs

We are still working on Server APIs for Server Components that work with the App Router

getAuth( req ) ( Page Router )

import { getAuth } from '@hellocoop/nextjs'
// returns same shape as useAuth().auth
const { 
    isLoggedIn, // always returned
    iat,        // returned if isLoggedIn == true
    sub,        // use as user identifier - returned if isLoggedIn == true
    // additional properties set in auth cookie - following are defaults
} = await getAuth( req )

Used in page routes to get the auth object.


<HelloProvider auth={auth}> </HelloProvider>

If you want to get the auth object from the auth cookie sever side, export getServerSideProps() and wrap your content in <HelloProvider auth={auth}>

import { HelloProvider, LoggedIn, LoggedOut, ContinueButton } from '@hellocoop/nextjs'
export default function MyPage = ({auth}) {
    const { name } = auth
        <HelloProvider auth={auth}> { // auth must be passed to HelloProvider }
                Hellō {name}
// This a convenience wrapper around `getAuth()`
export { getServerSideProps } from '@hellocoop/nextjs'


loggedInCallback( LoggedInParams ): LoggedInResponse

This is a callback you provide in the pageAuth() config that can do any logic you need when a user logs in. For example:

  • Determine if the user has access
  • Add roles or other properties to the auth cookie

See callback.login for details

import type { LoggedInParams, LoggedInResponse } from '@hellocoop/nextjs'
export default async loggedInCallback ({ 
        token,      // ID Token in compact, unparsed format
        payload,    // parsed ID Token payload
        req,        // NextApiRequest
        res         // NextApiResponse
    }:LoggedInParams): Promise<LoggedInResponse> => {
    // use sub claim as user identifier
    const { sub: id } = payload
    const user = async readUserTable(id)
    const role: Role = getUserRole(id)    
    // auth cookie will not be set
    if (!isRoleAuthorized(role)) 
        return {accessDenied: true}
    const { email, name, picture } = payload
    return { 
        // add role to auth object
        auth: { email, name, picture, role }