Next
This page will focus mainly on integrating Auth on the server-side with Next.js by implementing the Auth API.
To learn more about how to implement Auth on the client-side with Next.js (which you will likely need after implementing the server-side), see the Auth React page as Next uses React for the frontend:
If you want to interact with a working version of the Auth + Next integration that we'll be building in this guide, you can checkout the following GitHub repository, or clone it with the command below:
npx thirdweb create app --template thirdweb-auth-next
Getting Started
To add support for Auth to your Next backend, you'll need to install the @thirdweb-dev/auth
package (as well as any other packages you'll need for your wallet configuration, we'll need the ethers
package for this example as we'll be using the PrivateKeyWallet
):
Now we can setup our server with Auth using either the standard pages
directory, or the Next 13 app
directory. We'll explore how to use both setups below.
Pages Directory Setup
We can setup the server with the pages
directory by using the @thirdweb-dev/auth/next
entrypoint. First, we need to setup our Auth API by creating a new file called pages/api/auth/[...thirdweb].ts
:
Here, we first configure our ThirdwebAuth
instance with the domain
of our app used for anti-phishing, as well as the admin wallet used to issue and verify JWTs. In this case, we use the PrivateKeyWallet
from the @thirdweb-dev/auth/evm
entrypoint, but there are a number of other supported wallet setups, which you can learn more about on the wallet configuration page:
Finally, we export the ThirdwebAuthHandler
which sets up all the /api/auth/*
routes for us automatically. This is all the setup we need to setup a full Auth API on our Next.js backend!
App Router Setup
Alternatively, we can setup auth using the app router. We can setup our Auth API by creating a new file called app/api/auth/[...thirdweb]/route.ts
as follows:
Create a separate file named like thirdwebAuth.ts
:
Import thirdwebAuth.ts
in your app/api/auth/[...thirdweb]/route.ts
file:
Like above, we first configure our ThirdwebAuth
instance with the domain
of our app used for anti-phishing, as well as the admin wallet used to issue and verify JWTs. In this case, we use the PrivateKeyWallet
from the @thirdweb-dev/auth/evm
entrypoint, but there are a number of other supported wallet setups, which you can learn more about on the wallet configuration page:
Finally, we export the ThirdwebAuthHandler
which sets up all the /api/auth/*
routes for us automatically. This is all the setup we need to setup a full Auth API on our Next.js backend!
Usage
Authenticating the user on the server
The getUser
function can be used to authenticate the user on the server. It will return the user's address if the user is authenticated, or null
if the user is not authenticated. It can be used in any server-side context, including in Next.js API routes, as well as server-side functions like getServerSideProps
and getStaticProps
:
Validating the login request
By default, the Auth API will validate the login request by checking that the user requesting to login successfully signed a valid sign-in with wallet message. However, this doesn't perform specific checks on the exact contents of the payload, aside from the domain used for anti-phishing.
If you want to add specific checks to enforce the exact data on the login payload signed by users, you can use the authOptions
configuration:
Note that when you enforce these checks on the server-side, you'll also want to pass in the proper parameters to the login
function on your client-side application to ensure that the login payload gets the correct format. You can see an example of how to do this in the React section.
Prevent replay attacks
Since the sign-in with wallet payload is used to login to your server, it's important to prevent third parties from being able to reuse old login payloads to falsely authenticate as other users. This reuse of old login payloads is called a replay attack.
Luckily, all sign-in with wallet payloads include a nonce
field which is a random string generated when the request was created. If you are using a database, or have somewhere to store nonces, you can ensure that each nonce is only used once:
Changing the token validity duration
By default, the JWTs issued by the server are valid for 3 days (259200 seconds), after which the user will have to login again. If you want to change this duration, you can use the authOptions.tokenDurationInSeconds
configuration:
Changing the token refresh interval
As discussed above, each JWT has a validity duration for which it is valid, and once that duration passes, the JWT will no longer be accepted by the backend. In this case, the user would have to login again. However, for users who login frequently, having to re-login every few days would be an inconvenience.
This is where the refresh token flow comes in - for users who come back to your website frequently, they can get their valid JWTs refreshed to have an extended validity duration.
The refreshIntervalInSeconds
option allows you to configure how long after a JWT has initially been issued must pass before the token can be refreshed. Ideally, you don't want the token to be refresh too frequently because you'll received an unnecessary amount of requests to your API, but you want it to be refreshed frequently enough to increase convenience for frequently returning users. The default value for the refreshIntervalInSeconds
value is 3 hours (10800 seconds), meaning users who come back to your site after 3 hours of initially logging in will get their tokens refreshed.
Customizing cookie settings
The Auth API will set a cookie on the user's browser with the issued JWT token (learn more about cookie settings from the Mozilla cookie reference). This cookie is set to be httpOnly
and secure
(only sent over HTTPS), which is necessary for security purposes - and is also set to use the domain
of your API, with a path
of /
, and SameSite=None
.
If you want to overwrite these, settings, you can with the cookieOptions
configuration. For example, you may want to set your domain to be less specific - like if you have your api on api.example.com
and a client on client.example.com
, you may want to set your domain to .example.com
, or you want want to set your SameSite
setting to strict
if your API and client are on the same domain:
Saving users in your database
We can use the callbacks.onLogin
function to remember users in a database whenever they login, enabling a traditional database enabled authentication flow:
Enhancing session data
When the server issues a JWT, the default JWT claims are added to the token (as elaborated in the how auth works section). However, you may want to add additional data to the JWT claims to serve as session data that will persist on the token, such as certain user level permissions or access information. You can do this by returning data from the callbacks.onLogin
callback function which treats your return value as session data to store onto the JWT.
Enhancing user data
Alternatively, you can populate data about a user every time user data is requested from the /user
endpoint or getUser
function. This data is not session-wide as it is not stored on the JWT, so it isn't persisted an can change between requests. It can be useful for populating data that is not stored on the JWT, such as user profile information. We can do this by returning data from the callbacks.onUser
callback function.