Check out our Hellō Next.js Starter where you will be logging in with Hellō in less than a minute.
To add Hellō to your Next.js application, in your project directory:
npm install @hellocoop/nextjs
npx @hellocoop/quickstart-nextjs
This will launch the Hellō Quickstart web app. After logging into Hellō you will create or select an application, and the client_id
and a generated session secret will be added to your .env
file as HELLO_CLIENT_ID_DEFAULT
and HELLO_COOKIE_SECRET_DEFAULT
.
Include this .env
file in your deployments.
Create a hellocoop.js
file in the /pages/api
directory that contains:
import { HelloAuth } from '@hellocoop/nextjs'
export default HelloAuth({})
import { // only import buttons used
ContinueButton,
LoginButton,
UpdateEmailButton,
UpdatePictureButton
} from '@hellocoop/nextjs'
<ContinueButton/>
- provides [ ō Continue with Hellō ]
<LoginButton/>
- provides [ ō Login with Hellō ]
scope
- space separated list of Hellō scope values. Default 'openid email name picture'.targetURI
- defaults toHELLO_DEFAULT_TARGET_ROUTE
or '/'providerHint
- overrides the recommended providers
<UpdateEmailButton/>
- provides [ ō Update Email with Hellō ]
<UpdatePictureButton/>
- provides [ ō Update Picture with Hellō ]
targetURI
- defaults to current page.providerHint
- overrides the recommended providers
color
- white | blacktheme
- ignore-light | ignore-dark | aware-invert | aware-statichover
- pop | glow | flare | none
Explore styling with the button playground
import { logOut, logOutRoute } from '@hellocoop/nextjs'
logOut()
- function to logout user, loads logOutRoute
logOutRoute
- provides route to logout
import { LoggedIn, LoggedOut } from '@hellocoop/nextjs'
<LoggedIn>
<b>content displayed if logged in</b>
</LoggedIn>
<LoggedOut>
<i>content displayed if logged out</i>
</LoggedOut>
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()
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 )
If you want to show get the auth object from the auth cookie sever side, export getServerSideProps()
and wrap your content in <HelloProvider auth=({auth})>
// MyPage.tsx
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'
HELLO_COOKIE_SECRET
overridesHELLO_COOKIE_SECRET_DEFAULT
in.env
set by Quickstart.
This variable should be different from values checked into a repo.
HELLO_REDIRECT_URI
overrides dynamic redirect_uri discoveryHELLO_CLIENT_ID
overridesHELLO_CLIENT_ID_DEFAULT
in.env
set by Quickstart
HELLO_DOMAIN
- overrides 'hello.coop' - used for testing by Hellō teamHELLO_WALLET
- overrides default 'https://wallet.hello.coop' - used if mocking Hellō server
// /api/hellocoop.ts
import loggedIn from '@/src/your-logged-in-logic'
import HelloAuth from '@hellocoop/nextjs'
export default HelloAuth({
scope: ['email','name','picture'],
callbacks: {
loggedIn
},
pages: {
loggedIn: '/',
loggedOut:'/',
error: '/auth/error', // Error code passed in query string as ?error=
}
})
// src/your-logged-in-logic.ts
import type { LoggedInParams, LoggedInResponse } from '@hellocoop/nextjs'
export default async loggedIn ({ token, payload, req, res }:LoggedInParams)
: Promise<LoggedInResponse> => {
// use sub claim as user identifier
const { sub: id } = payload
const user = async readUserTable(id)
const authorizedUser: boolean = isUserAuthorized(user)
// no auth cookie set - redirected to error page
if (!authorizedUser)
return {isLoggedIn:false}
// no auth cookie set - process response directly
if (!authorizedUser) {
res.end(ErrorResponse)
return {
isLoggedIn: false
isProcessed: true
}
}
// choose what to store in auth cookie
return { auth: { email, name, picture }} = payload // default values
// process response and set auth cookie
const { email, name, picture } = payload
res.end(LoggedInPage({ email, name, picture }))
return {
processed: true,
auth: { email, name, picture }
}
}