Bring your own custom JWT Providers
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.
Custom JWT authentication is only supported with Web3Auth Plug and Play No Modal SDK
since the Web3Auth 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.
Check out this troubleshooting page to fix those..
Set up Custom JWT Verifier
To create a custom verifier for your JWT Providers, you'll need
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 etc.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}"
}
]
}JWT Validations
cautionYour JWT header must contain the
kid
field and the payload data must containiat
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. Theaud
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. Theiss
value is a case-sensitive string containing a StringOrURI value. Use of this claim is OPTIONAL.Token Subject (
sub
): The subject of the token. Thesub
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
- RSA
- ECDSA
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 enpoint: https://my-authz-server/.well-known/jwks.json
// Step 6. Create the JWT Verifier in Web3Auth Dashboard as per the above fields of JWT.
Using ECDSA 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 ecparam -name secp256k1 -genkey -noout -out ec-secp256k1-privateKey.pem
var privateKey = fs.readFileSync("ec-secp256k1-privateKey.pem");
// openssl ec -in ec-secp256k1-privateKey.pem -pubout -out ec-secp256k1-publicKey.pem
// var publicKey = fs.readFileSync("ec-secp256k1-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: "faj2720i2fdG7NsqzncndijwnKrthDvq43",
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: "ECDSA", 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 ecparam -name secp256k1 -genkey -noout -out ec-secp256k1-privateKey.pem
// This is the private key used to sign the JWT.
// Step 5. inside the vscode terminal type
// openssl ec -in ec-secp256k1-privateKey.pem -pubout -out ec-secp256k1-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 enpoint: 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",
blockExplorer: "https://etherscan.io",
ticker: "ETH",
tickerName: "Ethereum",
};
const web3auth = new Web3AuthNoModal({
clientId: "", // Web3Auth Client ID
chainConfig,
web3AuthNetwork: "saphhire_mainnet",
useCoreKitKey: false,
});
const privateKeyProvider = new EthereumPrivateKeyProvider({ config: { chainConfig } });
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)
const chainConfig = {
chainNamespace: CHAIN_NAMESPACES.EIP155,
chainId: "0x1",
rpcTarget: "https://rpc.ankr.com/eth",
displayName: "Ethereum Mainnet",
blockExplorer: "https://etherscan.io",
ticker: "ETH",
tickerName: "Ethereum",
};
const web3auth = new Web3AuthNoModal({
clientId: "", // Web3Auth Client ID
chainConfig,
web3AuthNetwork: "saphhire_mainnet",
useCoreKitKey: false,
});
const privateKeyProvider = new EthereumPrivateKeyProvider({ config: { chainConfig } });
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)
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",
blockExplorer: "https://etherscan.io",
ticker: "ETH",
tickerName: "Ethereum",
};
const web3auth = new Web3AuthNoModal({
clientId: "", // Web3Auth Client ID
chainConfig,
web3AuthNetwork: "saphhire_mainnet",
useCoreKitKey: false,
});
const privateKeyProvider = new EthereumPrivateKeyProvider({ config: { chainConfig } });
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
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
- Firebase:
If you are using a 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.
Create a Private Key using openssl.
openssl genrsa -out privateKey.pem 2048
This privateKey will be used to sign the token.
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.
Convert the publicKey.pem file to JWKS.
Now, look for a tool that converts
.pem
tojwk(s)
format.One of the tools is https://russelldavies.github.io/jwk-creator/
- Select Public Key Use:
Signing
- Algorithm:
RS256
- Key ID:
676da9d312c39a429932f543e6c1b6512e4983
// Use your own alphanumeric random string here. - PEM encoded key:
{paste-the-publicKey-pem-file-s-content-here}
- Select Public Key Use:
Click on
Convert
button.
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 aCustom JWT Verifier
on the Web3Auth Dashboard.