Let your users authenticate in a Next.js app with NFTs.
In this tutorial, we create our own instance of the IDP Kit locally and configure it to check users which want to authenticate for being an owner of a chosen NFT collection. We will register a client and connect it to Keycloak.
NFT collections can be hosted on the following ecosystems:
Ethereum
Polygon
Tezos
Near
Polkadot
Flow
The IDP Kit uses the OIDC authentication flow, the same technology used by Sign-in with Apple, Facebook, Twitter and many more. If you want to learn more about it and how it works behind the scenes, you can have a look at our concept section as well as how the ideas are translated when using NFTs.
IDP Kit Setup - Build and run the project in your local environment
Client Registration - Retrieve clientId and clientSecret from the IDP Kit, used by Keycloak
NFT Collection Configuration - Set NFT collection required by the users to login successfully
Keycloak - Register IDP-Kit as external Identity Provider with Keycloak
Frontend- Use Keycloak in a Next.js application (optional)
You can also watch the full tutorial here.
Before you start with the project setup, make sure you have the following dependencies on your local machine:
For running the project, you have two options: Docker or Gradle.
Cloning the project
git clone https://github.com/walt-id/waltid-idpkit.git2. Changing directory
cd waltid-idpkit3. Open the project in your feavourite IDEA
4. Create a walt.yaml file in the root directory of the project. Values needed are described in the configuration section.
5. Building the project
./gradlew build install6. Creating an alias (optional)
alias idpkit="build/install/waltid-idpkit/bin/waltid-idpkit"Cloning the project
git clone https://github.com/walt-id/waltid-idpkit.git2. Changing directory
cd waltid-idpkit3. Open the project in your feavourite IDEA
4. Create a walt.yaml file in the root directory of the project. Values needed are described in the configuration section.
4. Building the project
docker build --rm -t waltid/idpkit .5. Creating an alias (optional)
alias idpkit="docker run -p 8080:8080 -e WALTID_DATA_ROOT=/data -v $PWD:/data waltid/idpkit"Running the IDP-Kit Frontend The frontend with which the user will interact to authenticate by doing a connect wallet.
Change into the frontend directory
cd web/waltid-idpkit-ui/Install dependencies using node v.16
yarn install
or
npm installRunning the project
yarn dev
or
npm run devRun NFT-Kit JS (if ecosystem of your NFTs is not Ethereum or Polygon)
You also need to run the NFT Kit JS, if your NFT collection is not hosted on the Ethereum or Polygon network. Per default, the project will be run under "http://localhost:3000". We will need that in the NFT collection configuration.
Cloning the project
git clone https://github.com/walt-id/waltid-nftkit.git2. Changing directory
cd waltid-nftkit/js3. Run the following command
npm install4. Run the following command
npm i --save-dev @types/bn.js3. Run project
npm startWe need to provide the chain and the NFT collection, which the IDP Kit must check, when users are trying to log in. The values can be set in the config/idp-config.json under default_nft_token_claim
Choose the ecosystem of where your NFT collection is hosted
"default_nft_token_claim": {
"EVM": {
"chain": "MUMBAI",
"factorySmartContractAddress": "",
"smartContractAddress": "0x3496756a84E186DC8C0d7ef91BcD393200ef5Ebc",
"collectionPath": ""
}
}"default_nft_token_claim": {
"TEZOS": {
"chain": "GHOSTNET",
"factorySmartContractAddress": "",
"smartContractAddress": "KT1Rc59ukgW32e54aUdYqVzTM9gtHrA4JDYp",
"collectionPath": ""
}
}We also need to configure other properties in the same file:
"externalUrl": "http://localhost:8080",
"jsProjectExternalUrl":"http://localhost:3000"NFT collection configuration example:
"default_nft_token_claim": {
"NEAR": {
"chain": "TESTNET",
"factorySmartContractAddress": "",
"smartContractAddress": "demo.khaled_lightency1.testnet",
"collectionPath": ""
}
}We also need to configure other properties in the same file:
"externalUrl": "http://localhost:8080",
"jsProjectExternalUrl":"http://localhost:3000"NFT collection configuration example:
"default_nft_token_claim": {
"POLKADOT": {
"chain": "OPAL",
"factorySmartContractAddress": "",
"smartContractAddress": "1062",
"collectionPath": ""
}
}We also need to configure other properties in the same file:
"externalUrl": "http://localhost:5000",
"jsProjectExternalUrl":"http://localhost:4000""default_nft_token_claim": {
"FLOW": {
"chain": "TESTNET",
"factorySmartContractAddress": "",
"smartContractAddress": "0xa9ccb9756a0ee7eb",
"collectionPath": "/public/exampleNFTCollection"
}
}We also need to configure other properties in the same file:
"externalUrl": "http://localhost:8080",
"jsProjectExternalUrl":"http://localhost:3000"Now that we have finished the configuration, we need to rebuild the project for the changes to take effect, run the API and connect our client to it.
Rebuild the project
./gradlew build install2. Expose the API
idpkit runRebuild image
docker build --rm -t waltid/idpkit .2. Expose the API
idpkit runTo use the IDP Kits functionality, we need a client and collect client_id and client_secret. Those credentials will be used by Keycloak to make requests to the IDP Kit, which will in turn ask the user if they want to sign in and check if they are allowed to do so, based on the NFTs they hold in their wallet. After collecting the consent of the user and validating that they are allowed to log in, the IDP Kit will give Keycloak a secret with which it can request information about the authenticated the user.
The exchange of information between the client, which is in our case Keycloak and the authorization server which is the IDP Kit are based on the OpenID Connect standards. I won't go into more detail here, but you can learn more about it in the or watch this great from OktaDev, which gives a great overview about OpenID Connect. To understand how the base ideas are then translated to the NFT use case, you can dive into
Now that we know what we need and why we need it, let's go ahead and create our first client. Depending on the situation and personal preference, there are two options available: CLI tool, API.
To register a new client, we can use the clients register command provided under the OIDC scope of the CLI tool.
Parameter description
-n - Name of the client
-r - The redirect URL which should be used in the OIDC flow
Other Options:
--all-redirect-uris - Redirect can go to any URL specified in the OIDC flow requests
If we set a redirect URL we can make sure that no other party will be able to use our authentication flow, even if they would get access to our secrets. For our project we set the URL http://localhost:8082/realms/NFT/broker/nft/endpoint as this is the location where Keycloak wants us to redirect the user to. Later if we were to put keycloak into production it would be something like https://{host}/realms/NFT/broker/nft/endpoint. In this case we would need to update our registerd client and reflect the new redirect URL.
To update an existing client, we can use the clients register command provided under the OIDC scope of the CLI tool and add the -u flag to note that we want to change a client with the specified id.
Parameter description
-n - Name of the client
-r - The redirect URL which should be used in the OIDC flow
-u - The ID of the client we would like to update
CLI tool commands and options.
In order to use the API, we need to launch it first.
To register a new client, we can make a POST request to /api/oidc/clients/register. However, by default the , requires you to authenticate. Providing the master_token in the header of the request makes sure the registration goes through.
To get the master_token we can execute the clients token command under the OIDC scope of the CLI tool.
We need to replace master_token in the Authorization request header before executing.
Save the response somewhere, where you can later retrieve the information. Most importantly, the client_id and client_secret.
If we set a redirect URL we can make sure that no other party will be able to use our authentication flow, even if they would get access to our secrets. For our project we set the URL http://localhost:3000 as this will be the URL under which our frontend application will be hosed. Later if we were to put the application into production it would be something like https://applicationName.com. In this case we would need to update our registerd client and reflect the new redirect URL.
To update a client we make a PUT request to the /api/oidc/clients/<client_id> and provide the registration_access_token, which we got during client registration. In order for the update to go through, we need to provide the whole response we got from the client registration step in the update request body.
Make sure before executing the request, to replace the clientid in the request URL and the registration_access_token
API endpoints and options or visit the .
idpkit config --oidc clients register -n "myFrontend" -r "http://localhost:8001/realms/NFT/broker/nft/endpoint"idpkit config --oidc clients register -n "myFrontend" -r "https://applicationName.com" -u "client_id"idpkit runidpkit config --oidc clients tokencurl -X POST http://localhost:8080/api/oidc/clients/register \
-H "Authorization: Bearer master_token" \
-H "Content-Type: application/json" \
-d '{"client_name": "MyApp","redirect_uris": ["http://localhost:3000/api/auth/callback/walt-id-nft"],"all_redirect_uris": false}'curl -X PUT http://localhost:8080/api/oidc/clients/96baIcn5YUD7z2H69nPkd1KrizaixBs3IWcRS_qDCmM \
-H "Authorization: Bearer eyJraWQiOiI2YzA2M2Y3NjBjNGM0M2VlYjNkMDNmNmQzODQ1NGU1OSIsInR5cCI6IkpXVCIsImFsZyI6IlJTMjU2In0.eyJzdWIiOiI5NmJhSWNuNVlVRDd6Mkg2OW5Qa2QxS3JpemFpeEJzM0lXY1JTX3FEQ21NIn0.RgNdqkK_o2paGvJhM95jtrEqUPTiIQVB4kZFY8QIAKypAFC2Iq6WTll_nyAM_osbSluEQGlQvwpFf4xnF4aM2JxAkeTE1SCHA3EWODIn2uDzKDFkpNOdw9xJHiIstqy2WK1x8jsi1RK_iaa6gf_3Pm0xazEekkjvRGtXn9jfoyYiUVN75EJDU_pbSju9vXNIO2nd2FIBzmyd3DWohat0Lgb1m7fv8eFWXjC-PYICrv-qLP7-cVuhNnrkmCXSIwhXcXbdjyqAB6cgFVqecUaiTCi928uIxTRsAS7_vnPCiWxnPTGCTGsE05hspbnTuubxs0oYGFOZ7adURvCkgxFsHw" \
-H "Content-Type: application/json" \
-d '{"client_secret_expires_at": 0, "all_redirect_uris": false, "registration_client_uri": "http://localhost:8080/api/oidc/clients/96baIcn5YUD7z2H69nPkd1KrizaixBs3IWcRS_qDCmM", "redirect_uris": ["http://localhost:3000"], "client_id_issued_at": 1662617990, "client_secret": "hMAi7khf6cgZ2wRXlN89FQ1zB99654j8cyF4O3AAmk0", "client_name": "MyApp", "registration_access_token": "eyJraWQiOiI2YzA2M2Y3NjBjNGM0M2VlYjNkMDNmNmQzODQ1NGU1OSIsInR5cCI6IkpXVCIsImFsZyI6IlJTMjU2In0.eyJzdWIiOiI5NmJhSWNuNVlVRDd6Mkg2OW5Qa2QxS3JpemFpeEJzM0lXY1JTX3FEQ21NIn0.RgNdqkK_o2paGvJhM95jtrEqUPTiIQVB4kZFY8QIAKypAFC2Iq6WTll_nyAM_osbSluEQGlQvwpFf4xnF4aM2JxAkeTE1SCHA3EWODIn2uDzKDFkpNOdw9xJHiIstqy2WK1x8jsi1RK_iaa6gf_3Pm0xazEekkjvRGtXn9jfoyYiUVN75EJDU_pbSju9vXNIO2nd2FIBzmyd3DWohat0Lgb1m7fv8eFWXjC-PYICrv-qLP7-cVuhNnrkmCXSIwhXcXbdjyqAB6cgFVqecUaiTCi928uIxTRsAS7_vnPCiWxnPTGCTGsE05hspbnTuubxs0oYGFOZ7adURvCkgxFsHw", "client_id": "96baIcn5YUD7z2H69nPkd1KrizaixBs3IWcRS_qDCmM"}' \Since the IDP Kit is compliant with the well adopted OpenID Connect standard for identity provision, it can be easily integrated, as a federated identity provider on Keycloak.
Assuming that you already have a local instance of Keycloak running, we will continue with the configuration of our federated identity provider. In case you need to setup Keycloak first, please have a look at their documentation on how to get started.
To start with the configuration, we log in to the KeyCloak administration console with our admin credentials and navigate to the realm, for which we want to apply the configuration.
In the admin console, we navigate to the Identity Providers section in the left menu bar and open the "Add provider..." drop-down menu and choose "OpenID Connect v1.0":
2. We fill out Alias and Display Name according to how we want the IDP Kit to be referred to in the Login UI
3. We scroll down to Import External IDP Config and enter the URL of the well-known OIDC discovery document of the IDP Kit and click import. For our IDP Kit which is running locally, this would be:
http://localhost:8080/api/oidc/.well-known/openid-configuration
We need to make sure IDP Kit is running, as Keycloak will import all the information it needs from that endpoint as soon as we press "Import".
4. Now we scroll down to Client Authentication and choose Client secret sent as basic auth as input field value. Then we provide Client ID and Client Secret which we got during the client registration step.
5. To make sure the IDP-Kit uses our NFT config settings during authentication, we need to provide openid nft_token as the value for Default Scopes and set Prompt to None
6. Now we can create the provider.
Now that we've finished the setup of our Identity provider in Keycloak, we must make sure that the client we registered with the IDP-Kit has the correct redirect URL. The redirect URL should match the value found at Redirect URI in our just created Identity Provider.
In case the redirect URL registered with our IDP-Kit client does not match, we need to make a change.
To update an existing client, we can use the clients register command provided under the OIDC scope of the CLI tool and add the -u flag to note that we want to change a client with the specified id.
idpkit config --oidc clients register -n "myFrontend" -r "http://localhost:8082/realms/NFT/broker/nft/endpoint" -u "client_id"Parameter description
-n - Name of the client
-r - The redirect URL which should be used in the OIDC flow
-u - The ID of the client we would like to update
After updating the client, we can now run the IDP-Kit and connect Keycloak to an application of our choice. We will be using Next.js and NextAuth.
We have prepared a which we can use as a starting point. It uses NextAuth.js for handling authentication, which makes it easy for us to connect our Keycloak instance. We won't go into details of how Next.js or NextAuth.js works.
The user of the frontend application needs or another to share their blockchain address, with which the IDP Kit will be able to check if the user is holder of the required NFT collection.
We will need and or npm
We will clone the project and install all dependencies
2. Change directories
3. Install dependencies
We log in to the KeyCloak administration console with our admin credentials and navigate to the realm, we used before to configure our external identity provider.
2. Under the Clients section, we create a new client, which we will use in our Next.js app.
3. We provide a Client ID and Name and click on Next.
4. We select Client authentication and the Standard flow and click Save.
5. In the overview of the new client we just created under the General Settings section, we update Valid redirect URIs to match our next.js application nextAuth callback URL: http://localhost:3000/api/auth/callback/keycloak
Now that we have the client registered with Keycloak we can add its credentials in our Next.js application.
Let's rename .env.example file to .env
We assign CLIENT_ID and CLIENT_SECRET to the values find in Settings and in the Credentials section respectively of our just created Keycloak client.
The ISSUER we set to the host of our Keycloak instance.
Those values will then be used by the build in NextAuth.js provider for Keycloak which can be found in pages/api/auth/[...nextauth].ts
Now that we have finished all configurations, we can start up our frontend.
Now we can log in as long as we hold an NFT of the collection we specified in the .
You made it, you've built login with NFTs with Keycloak and Next.js! Share your progress in our channel or on , then we can celebrate together 🤟
git clone https://github.com/walt-id/waltid-nft-auth-keycloak-nextjs.gitcd waltid-nft-auth-keycloak-nextjsyarn installyarn dev








Since the IDP Kit is compliant with the well adopted OpenID Connect standard for identity provision, it can be easily integrated, as a federated identity provider on Keycloak.
Assuming that you already have a local instance of Keycloak running, we will continue with the configuration of our federated identity provider. In case you need to setup Keycloak first, please have a look at their documentation on how to get started.
Important: There are currenlty some issues with the versions >19.0.1 of Keycloak. Please use Keycloak 18.0.2 or Keycloak 20 for a smooth experience.
To start with the configuration, we log in to the KeyCloak administration console with our admin credentials and navigate to the realm, for which we want to apply the configuration.
In the admin console, we select under configurations the Identity providers and select the OpenID Connect v1.0 option
2. We fill out Alias and Display Name
3. Add the Discovery endpoint, which will be in the form of:
{host}/api/oidc/.well-known/openid-configuration
We need to make sure IDP Kit is running, as Keycloak will import all the information it needs from that endpoint.
4. Provide Client ID and Client Secret which we got during the client registration step
After successfully creating the new identity provider, in the Advanced settings section when expanding the Advanced dropdown, we need to update Scopes and Prompt
Scopes = openid nft_token
Prompt = None
By updating the scopes to use nft_token, we make sure the IDP-Kit will use NFTs as a method of authentication, when the user logs in.
Now that we've finished the setup of our Identity provider in Keycloak, we must make sure that the client we registered with the IDP-Kit has the correct redirect URL. The redirect URL should match the value found in at Redirect URI in our just created Identity Provider.
In case the redirect URL registered with our IDP-Kit client does not match, we need to make a change.
To update an existing client, we can use the clients register command provided under the OIDC scope of the CLI tool and add the -u flag to note that we want to change a client with the specified id.
idpkit config --oidc clients register -n "myFrontend" -r "http://localhost:8082/realms/NFT/broker/nft/endpoint" -u "client_id"Parameter description
-n - Name of the client
-r - The redirect URL which should be used in the OIDC flow
-u - The ID of the client we would like to update
After updating the client, we can now run the IDP-Kit and connect Keycloak to an application of our choice. We will be using Next.js and NextAuth.



