Next.js
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.
Setup
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
2. HELLO_COOKIE_SECRET
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: [
'cdn.hello.coop',
'pictures.hello.coop',
'www.gravatar.com'
]
}
}
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:
import { Html, Head, Main, NextScript } from 'next/document'
export default function Document() {
return (
<Html>
<Head>
<link rel="stylesheet" href="https://cdn.hello.coop/css/hello-btn.css"/>
</Head>
</Html>
)
}
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:
project-directory/
├─ .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
Buttons
The following buttons are available:
import {
ContinueButton,
LoginButton,
UpdateProfileButton
} from '@hellocoop/nextjs/react'
Note they are in
@hellocoop/nextjs/react
See the SDK Reference | React for details.
Components
The following React components are available:
import {
HelloProvider,
LoggedIn,
LoggedOut,
} from '@hellocoop/nextjs/react'
Note they are in
@hellocoop/nextjs/react
See the SDK Reference | React for details.
Client APIs
useAuth()
import { useAuth } from '@hellocoop/nextjs'
const {
isLoading, // useSWR response, true if still loading call to
isLoggedIn,
auth: undefined | {
isLoggedIn, // always returned
iat, // returned if isLoggedIn == true
sub, // use as user identifier - returned if isLoggedIn == true
// additional claims - following are defaults
name,
email,
picture
}
} = useAuth()
logOut()
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
name,
email,
picture
} = await getAuth( req )
Used in page routes to get the auth object.
getServerSideProps()
<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
return(
<HelloProvider auth={auth}> { // auth must be passed to HelloProvider }
<LoggedIn>
Hellō {name}
</LoggedIn>
<LoggedOut>
<ContinueButton/>
</LoggedOut>
</HelloProvider>
)
}
// This a convenience wrapper around `getAuth()`
export { getServerSideProps } from '@hellocoop/nextjs'
loginSync()
loginSync( LoginSyncParams ): LoginSyncResponse
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 }
}
}