Skip to main content

Bring your own custom JWT Provider

You can incorporate your login providers by utilizing one of the custom login schemes, including RSA or ECDSA signatures. By doing so, your users can continue using your current login providers or your custom authentication scheme.

info

Custom JWT authentication is only supported with Web3Auth Plug and Play No Modal SDK since the Web3Auth PnP Modal SDK will only help you configure the social logins within the Modal UI.

For signing the JWT, your application must follow the JWT specification and use the private key corresponding to the JWKS. And the public keys of the JWT should be exposed through an endpoint, which is used by Web3Auth to verify the JWT.

Facing issue with JWT?

Set up Custom JWT Verifier

Custom JWT Provider on Web3Auth Dashboard

To create a custom verifier for your JWT Providers, you'll need

  1. JWT Verifier ID: JWT Verifier ID is the unique identifier to publicly represent a user on a verifier. e.g: sub, email, or even a custom field of your JWT payload that is unique in your system for each user.

  2. JWK Endpoint: An endpoint containing the JWKS used for signing the JWT.

    Check What are JWKS and How to create one from PEM to learn how to create JWKS.

    Your JWKS must have the following fields.
    {
    "keys": [
    {
    "kty": "RSA",
    "kid": "{your_kid}",
    "use": "sig",
    "alg": "RS256",
    "n": "{your_n}",
    "e": "{your_e}"
    }
    ]
    }
  3. JWT Validations

    warning

    Your JWT header must contain the kid field and the payload data must contain the iat field.

    You can add up to 3 validation fields, including any claims like aud, sub, iss, email_verified etc. These are the claims against which a JWT is validated.

    Here are a couple of examples to be used in validation:

    • Token Audience ( aud ): The "aud" (audience) claim identifies the recipients for which the JWT is intended. Each principal intended to process the JWT MUST identify itself with a value in the audience claim. If the principal processing the claim does not identify itself with a value in the "aud" claim when this claim is present, then the JWT will be rejected. The aud value is a case-sensitive string containing a StringOrURI value. The interpretation of audience values is generally application-specific.

    • Token Issuer ( iss ): The issuing authority of the token. The iss value is a case-sensitive string containing a StringOrURI value. Use of this claim is OPTIONAL.

    • Token Subject ( sub ): The subject of the token. The sub value is a case-sensitive string containing a StringOrURI value. Use of this claim is OPTIONAL.

    • Token Email Verified ( email_verified ): The email verified claim is a boolean value that indicates whether the email address has been verified.

Using jsonwebtoken to generate JWT

Using RSA for JWT Signing

// Step 1. npm init -y
// Step 2. npm install jsonwebtoken
// Step 3. create an index.js file and paste the below code
import jwt from "jsonwebtoken";
import fs from "fs";
// openssl genrsa -out privateKey.pem 2048
var privateKey = fs.readFileSync("privateKey.pem");
// openssl rsa -in privateKey.pem -pubout -out publicKey.pem
// var publicKey = fs.readFileSync("publicKey.pem");
// https://my-authz-server/.well-known/jwks.json -> publicKey to be used in Custom Authentication as JWK Endpoint.
// Check out below to convert PEM to JWKS

var token = jwt.sign(
{
sub: "faj2720i2fdG7NsqznOKrthDvq43", // must be unique to each user
name: "Mohammad Shahbaz Alam",
email: "shahbaz@web3auth.io",
aud: "urn:my-resource-server", // -> to be used in Custom Authentication as JWT Field
iss: "https://my-authz-server", // -> to be used in Custom Authentication as JWT Field
iat: Math.floor(Date.now() / 1000),
exp: Math.floor(Date.now() / 1000) + 60 * 60,
},
privateKey,
{ algorithm: "RS256", keyid: "1bb9605c36e69386830202b2d" }, // <-- Replace it with your kid. This has to be present in the JWKS endpoint.
);

console.log(token);
// Step 4. open terminal inside the vscode and type
// openssl genrsa -out privateKey.pem 2048
// This is the private key used to sign the JWT.
// Step 5. inside the vscode terminal type
// openssl rsa -in privateKey.pem -pubout -out publicKey.pem
// This is the public key used to verify the JWT. This is the key that is used to make JWKS.
// Check out below to convert PEM to JWKS
// Store it in gist, public folder or somewhere else that is accessible to the public.
// like this endpoint: https://my-authz-server/.well-known/jwks.json
// Step 6. Create the JWT Verifier in Web3Auth Dashboard as per the above fields of JWT.

See this to set up the custom jwt verifier using the above JWT data on the Web3Auth Dashboard.

Login with JWT (idToken - jsonwebtoken)

const chainConfig = {
chainNamespace: CHAIN_NAMESPACES.EIP155,
chainId: "0x1",
rpcTarget: "https://rpc.ankr.com/eth",
displayName: "Ethereum Mainnet",
blockExplorerUrl: "https://etherscan.io",
ticker: "ETH",
tickerName: "Ethereum",
logo: "https://images.toruswallet.io/ethereum.svg",
};

const privateKeyProvider = new EthereumPrivateKeyProvider({ config: { chainConfig } });

const web3auth = new Web3AuthNoModal({
clientId: "", // Web3Auth Client ID
web3AuthNetwork: "saphhire_mainnet",
privateKeyProvider: privateKeyProvider,
useCoreKitKey: false,
});

const openloginAdapter = new OpenloginAdapter({
adapterSettings: {
uxMode: "redirect", // redirect or popup
loginConfig: {
jwt: {
verifier: "verifier-name", // name of the verifier created on Web3Auth Dashboard
typeOfLogin: "jwt",
clientId: "", // Web3Auth Client ID
},
},
},
privateKeyProvider,
});

await web3auth.connectTo(WALLET_ADAPTERS.OPENLOGIN, {
loginProvider: "jwt",
extraLoginOptions: {
id_token: "YOUR_GENERATED_ID_TOKEN",
verifierIdField: "sub", // sub, email, or custom
},
});

Using jose to generate JWT

// Step 1. npm init -y && npm install jose
// Step 2. create an index.js file and paste the below code
import * as jose from "jose";
import fs from "fs";
// openssl genrsa -out privateKey.pem 2048
var privateKey = fs.readFileSync("privateKey.pem");
// openssl rsa -in privateKey.pem -pubout -out publicKey.pem
var publicKey = fs.readFileSync("publicKey.pem");
// https://my-authz-server/.well-known/jwks.json -> to be used in Custom Authentication as JWK Endpoint.

// Signing the JWT
const jwt = await new jose.SignJWT({ "urn:example:claim": true })
.setProtectedHeader({ alg: "RS256", kid: "1bb9605c36e69386830202b2d" }) // <-- Replace it with your kid. This has to be present in the JWKS endpoint.
.setIssuedAt()
.setIssuer("https://my-authz-server")
.setAudience("urn:my-resource-server")
.setExpirationTime("2h")
.sign(privateKey);

console.log(jwt);

// Verifying the JWT using Remote JWK Set.
// This is just to show how the Verify works, look above to set-up custom jwt verifier on the Web3Auth Dashboard.
const JWKS = jose.createRemoteJWKSet(new URL("https://my-authz-server/.well-known/jwks.json"));

const { payload, protectedHeader } = await jose.jwtVerify(jwt, JWKS, {
issuer: "https://my-authz-server",
audience: "urn:my-resource-server",
});

console.log(protectedHeader);
console.log(payload);

See this to set up the custom jwt verifier using the above JWT data on the Web3Auth Dashboard.

Login with JWT (idToken - jose)

Example
const chainConfig = {
chainNamespace: CHAIN_NAMESPACES.EIP155,
chainId: "0x1",
rpcTarget: "https://rpc.ankr.com/eth",
displayName: "Ethereum Mainnet",
blockExplorerUrl: "https://etherscan.io",
ticker: "ETH",
tickerName: "Ethereum",
logo: "https://images.toruswallet.io/ethereum.svg",
};

const privateKeyProvider = new EthereumPrivateKeyProvider({ config: { chainConfig } });

const web3auth = new Web3AuthNoModal({
clientId: "", // Web3Auth Client ID
web3AuthNetwork: "saphhire_mainnet",
useCoreKitKey: false,
privateKeyProvider: privateKeyProvider,
});

const openloginAdapter = new OpenloginAdapter({
adapterSettings: {
uxMode: "redirect", // redirect or popup
loginConfig: {
jwt: {
verifier: "verifier-name", // name of the verifier created on Web3Auth Dashboard
typeOfLogin: "jwt",
clientId: "", // Web3Auth Client ID
},
},
},
privateKeyProvider,
});

await web3auth.connectTo(WALLET_ADAPTERS.OPENLOGIN, {
loginProvider: "jwt",
extraLoginOptions: {
id_token: "YOUR_GENERATED_ID_TOKEN",
verifierIdField: "sub", // sub, email, or custom
},
});

Using passport-jwt to generate JWT

jwks-rsa - Passport Example

The jwks-rsa library provides a small helper that makes it easy to configure passport-jwt with the RS256 algorithm. Using passportJwtSecret you can generate a secret provider that will provide the right signing key to passport-jwt based on the kid in the JWT header.

// Step 1. npm init -y && npm install passport-jwt
// Step 2. create an index.js file and paste the below code
const Express = require('express');
const passport = require('passport');
const JwtStrategy = require('passport-jwt').Strategy;
const ExtractJwt = require('passport-jwt').ExtractJwt;
const jwksRsa = require('jwks-rsa');

...
// Initialize the app.
const app = new Express();

passport.use(
new JwtStrategy({
// Dynamically provide a signing key based on the kid in the header and the signing keys provided by the JWKS endpoint.
secretOrKeyProvider: jwksRsa.passportJwtSecret({
cache: true,
rateLimit: true,
jwksRequestsPerMinute: 5,
jwksUri: `https://my-authz-server/.well-known/jwks.json`
}),
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),

// Validate the audience and the issuer.
audience: 'urn:my-resource-server',
issuer: 'https://my-authz-server',
algorithms: ['RS256']
},
verify)
);

app.use(passport.initialize());

See this to set up the custom jwt verifier using the above JWT data on the Web3Auth Dashboard.

Login with JWT (idToken - passport-jwt)

Example
import { Web3AuthNoModal } from "@web3auth/no-modal";
import { EthereumPrivateKeyProvider } from "@web3auth/ethereum-provider";
import { OpenloginAdapter } from "@web3auth/openlogin-adapter";

const chainConfig = {
chainNamespace: CHAIN_NAMESPACES.EIP155,
chainId: "0x1",
rpcTarget: "https://rpc.ankr.com/eth",
displayName: "Ethereum Mainnet",
blockExplorerUrl: "https://etherscan.io",
ticker: "ETH",
tickerName: "Ethereum",
logo: "https://images.toruswallet.io/ethereum.svg",
};

const privateKeyProvider = new EthereumPrivateKeyProvider({ config: { chainConfig } });

const web3auth = new Web3AuthNoModal({
clientId: "", // Web3Auth Client ID
web3AuthNetwork: "saphhire_mainnet",
useCoreKitKey: false,
privateKeyProvider: privateKeyProvider,
});

const openloginAdapter = new OpenloginAdapter({
adapterSettings: {
uxMode: "redirect", // redirect or popup
loginConfig: {
jwt: {
verifier: "verifier-name", // name of the verifier created on Web3Auth Dashboard
typeOfLogin: "jwt",
clientId: "", // Web3Auth Client ID
},
},
},
privateKeyProvider,
});

await web3auth.connectTo(WALLET_ADAPTERS.OPENLOGIN, {
loginProvider: "jwt",
extraLoginOptions: {
id_token: "YOUR_GENERATED_ID_TOKEN",
verifierIdField: "sub", // sub, email, or custom
},
});

Filled Custom JWT Verifier

Custom JSON Web Token Provider on Web3Auth Dashboard

What are JWKS?

JWKS stands for JSON Web Key Set. It is a set of keys containing the public keys that should be used to verify any JSON Web Token (JWT) issued by the authorization server and signed using the RS256 signing algorithm.

How to create JWKS?

  • Most of the login providers that support JWT-based login will provide you this URL, such as Firebase, Google, Auth0, AWS Cognito etc.

    • Firebase: https://www.googleapis.com/service_accounts/v1/jwk/{your-project-id}
    • Auth0: https://{your-domain}/.well-known/jwks.json
    • Google: https://www.googleapis.com/oauth2/v3/certs
    • AWS Cognito: https://cognito-idp.{region}.amazonaws.com/{userPoolId}/.well-known/jwks.json
  • If you are using your own custom JWT, you will need to convert your PEM file to JWKS.

How to convert PEM to JWKS?

If you're using jose or jsonwebtoken library, you can use the following steps to convert your PEM file to JWKS.

  1. Create a Private Key using openssl.

    openssl genrsa -out privateKey.pem 2048

    This privateKey will be used to sign the token.

  2. Using the above privateKey.pem file, create a Public Key.

    openssl rsa -in privateKey.pem -pubout -out publicKey.pem

    This publicKey.pem file will be converted to JWKS.

  3. Convert the publicKey.pem file to JWKS.

    Now, look for a tool that converts .pem to jwk(s) format.

    • One of the tools is https://pem2jwk.vercel.app/

      • Select Signing Algorithm: RS256
      • Select Public Key Use: Signing
      • Key ID: paste-yours or leave it blank to generate a random one.
      • PEM encoded key: {paste-the-publicKey-pem-file-s-content-here}
    • Click on the Convert to JWK button.

      JWKS Convert Tool

  4. To complete the process, you need to save the output as a .json file, host it on your server, and make sure it's publicly accessible.

    This will give you the JWKS Endpoint, which is required when setting up a Custom JWT Verifier on the Web3Auth Dashboard.