Skip to main content

Authentication in MPC Core Kit JS SDK

There are two ways to login your users, depending on the type of authentication method you've chosen. If you are looking for an Authentication Flow in your application (like Auth0 SPA Flow), you can use the loginWithOAuth() function. If you are looking to pass a JWT-based IdToken to the SDK from your application (like Auth0 RWA Flow or even BYOA JWT provider), you can use the loginWithJWT() function.

As a prerequisite, before triggering the login function, you need to create a verifier for your login method on the Web3Auth Dashboard.

Creating a Verifier

Since this is a Core Kit SDK, it does not provide any default authentication methods. You need to create a custom verifier to use this SDK. This means that you need to authenticate users with your own custom authentication service. For example, while authenticating with Google, you have to use your own Google Client ID and Dashboard to authenticate users directly or use aggregate services like Auth0, Firebase, AWS Cognito etc. Additionally, you can make your own JWT token authentication system and pass over the ID Token to Web3Auth to generate a private key for them.

For enabling this, you need Create a Verifier from the Custom Auth section of the Web3Auth Developer Dashboard with your desired configuration.

tip

If you want to know more about setting up a verifier and how to use it, please refer to the Custom Authentication Documentation.

warning

Core Kit SDK only supports Sapphire Mainnet and Devnet networks. The other networks don't support MPC functionalities.

Log In with OAuth

loginWithOauth(loginParams: OauthLoginParams): Promise<void>;

VariableTypeDescriptionMandatory
loginParamsobjectLogin ParametersYes
React Native

While using the application in React Native, you can use the ux_mode as react-native, this helps you to use the SDK in a React Native environment. However, the implicit login flow doesn't work in React Native, you need to manually call the login with JWT function for it after getting the JWT token from the auth provider.

OauthLoginParams

ParameterTypeDescriptionMandatory
subVerifierDetailsSubVerifierDetailsDetails of the verifier the app needs to connect to. This is named a "sub verifier" to accommodate for aggregate verifiers as well.Yes
aggregateVerifierIdentifier?stringIdentifier/ Name of the aggregate verifier you've made on the Web3Auth Dashboard. Not needed if you're connecting to a single verifier.No
subVerifierDetailsArray?SubVerifierDetails[]Array of the details of verifiers the app needs to connect to.No

SubVerifierDetails

Contains the details of the verifier the app needs to connect to. Use this in the case of a single verifier.

ParameterTypeDescriptionMandatory
typeOfLoginTypeOfLoginType of login of this verifier, this value will affect the login flow that is adapted. For example, if you choose google, a Google sign-in flow will be used. If you choose jwt, you should be providing your own JWT token, no sign-in flow will be presented.Yes
verifierstringName/ Identifier of the verifier/ sub verifier in case of aggregate verifiers, you'd like your app to connect to.Yes
clientIdstringClient Id given by the auth provider. Pass a random string in case you're connecting to a JWT based setup.Yes

AggregateVerifierLoginParams

Contains the details of an aggregate verifier the app needs to connect to. Use this in case of an aggregate verifier.

ParameterTypeDescriptionMandatory
aggregateVerifierIdentifierstringThe name of your aggregate verifierYes
subVerifierDetailsArraySubVerifierDetails[]An array containing the details of your sub verifiers.Yes
aggregateVerifierType?AGGREGATE_VERIFIER_TYPEWhat kind of aggregation is needed for your aggregate verifier? Use "single_id_verifier" by default in most casesNo

Usage

General Verifier

import { Web3AuthMPCCoreKit, SubVerifierDetailsParams } from "@web3auth/mpc-core-kit";

const verifierConfig = {
subVerifierDetails: {
typeOfLogin: "google",
verifier: "w3a-google-demo",
clientId: "519228911939-cri01h55lsjbsia1k7ll6qpalrus75ps.apps.googleusercontent.com",
},
} as SubVerifierDetailsParams;

await coreKitInstance.loginWithOauth(verifierConfig);

Aggregate Verifier

import { Web3AuthMPCCoreKit, AggregateVerifierLoginParams } from "@web3auth/mpc-core-kit";

const verifierConfig = {
aggregateVerifierIdentifier: "aggregate-sapphire",
subVerifierDetailsArray: [
{
typeOfLogin: "google",
verifier: "w3a-google",
clientId: "774338308167-q463s7kpvja16l4l0kko3nb925ikds2p.apps.googleusercontent.com",
},
],
} as AggregateVerifierLoginParams;

await coreKitInstance.loginWithOauth(verifierConfig);

If you're using the popup mode (default) in your application, while logging in, you need to have a service worker running, which essentially catches the login redirect and sends it back to the main DOM with the parameters. These parameters are then used to log in the user with Web3Auth.

Service Worker

A service worker is a script that is run by the browser. It does not have any direct relationship with the DOM and provides many out-of-the-box network-related features. Web3Auth Core Kit tKey SDK needs a service worker relative to baseUrl to capture the auth redirect at redirectPathName path.

For example, while using service worker if baseUrl is https://your-domain.com/serviceworker then the user will be redirected to the https://your-domain.com/serviceworker/redirect page after logging in where the service worker will capture the results and send it back to the original window where login was initiated.

tip
  • Using a service worker is required only in the popup flow.

  • A service worker is needed if you are using popup uxMode within your MPC Core Kit Configuration.

  • For browsers where service workers are not supported, or in the case you wish to not use service workers, create and serve redirect page (i.e. redirect.html file).

Service Worker Setup

  • If you're using React, to set up service worker, you need to create a sw.js file in your public folder and register it in your index.html file. You can find more information about it in this blog.

  • For Angular, this guide will be helpful in setting up the service worker.

  • For Vue, this guide is a great way to get started with service workers.

Service Worker Code

You can directly copy the service worker file code from here and paste it into your respective folder. You can also find the code in our MPC Core Kit Example (Popup Flow).

Service Worker Code
/public/serviceworker/sw.js
/* eslint-disable */
function getScope() {
return self.registration.scope;
}

self.addEventListener("message", function (event) {
if (event.data && event.data.type === "SKIP_WAITING") {
self.skipWaiting();
}
});

self.addEventListener("fetch", function (event) {
try {
const url = new URL(event.request.url);
if (url.pathname.includes("redirect") && url.href.includes(getScope())) {
event.respondWith(
new Response(
new Blob(
[
`
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width,initial-scale=1.0" />
<title>Redirect</title>
<style>
* {
box-sizing: border-box;
}

html,
body {
background: #fcfcfc;
height: 100%;
padding: 0;
margin: 0;
}

.container {
width: 100%;
height: 100%;

display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
}

h1.title {
font-size: 14px;
color: #0f1222;
font-family: "Roboto", sans-serif !important;
margin: 0;
text-align: center;
}

.spinner .beat {
background-color: #0364ff;
height: 12px;
width: 12px;
margin: 24px 2px 10px;
border-radius: 100%;
-webkit-animation: beatStretchDelay 0.7s infinite linear;
animation: beatStretchDelay 0.7s infinite linear;
-webkit-animation-fill-mode: both;
animation-fill-mode: both;
display: inline-block;
}

.spinner .beat-odd {
animation-delay: 0s;
}

.spinner .beat-even {
animation-delay: 0.35s;
}

@-webkit-keyframes beatStretchDelay {
50% {
-webkit-transform: scale(0.75);
transform: scale(0.75);
-webkit-opacity: 0.2;
opacity: 0.2;
}

100% {
-webkit-transform: scale(1);
transform: scale(1);
-webkit-opacity: 1;
opacity: 1;
}
}

@keyframes beatStretchDelay {
50% {
-webkit-transform: scale(0.75);
transform: scale(0.75);
-webkit-opacity: 0.2;
opacity: 0.2;
}

100% {
-webkit-transform: scale(1);
transform: scale(1);
-webkit-opacity: 1;
opacity: 1;
}
}

@media (min-width: 768px) {
h1.title {
font-size: 14px;
}
p.info {
font-size: 28px;
}

.spinner .beat {
height: 12px;
width: 12px;
}
}
</style>
</head>

<body>
<div id="message" class="container">
<div class="spinner content" id="spinner">
<div class="beat beat-odd"></div>
<div class="beat beat-even"></div>
<div class="beat beat-odd"></div>
</div>
<h1 class="title content" id="closeText" style="display: none;">You can close this window now</h1>
</div>
<script
src="https://scripts.toruswallet.io/broadcastChannel_5_0_2.js"
integrity="Bu0bRAeSlh2jpBuUxKk5ivkdotaHH37cQ2XiV20EmFJmghb41D0f8xME/M1WZxFC"
></script>
<script>
function storageAvailable(type) {
var storage;
try {
storage = window[type];
var x = "__storage_test__";
storage.setItem(x, x);
storage.removeItem(x);
return true;
} catch (e) {
return (
e &&
// everything except Firefox
(e.code === 22 ||
// Firefox
e.code === 1014 ||
// test name field too, because code might not be present
// everything except Firefox
e.name === "QuotaExceededError" ||
// Firefox
e.name === "NS_ERROR_DOM_QUOTA_REACHED") &&
// acknowledge QuotaExceededError only if there's something already stored
storage &&
storage.length !== 0
);
}
}
function showCloseText() {
var closeText = document.getElementById("closeText");
var spinner = document.getElementById("spinner");
if (closeText) {
closeText.style.display = "block";
}
if (spinner) {
spinner.style.display = "none";
}
}
var isLocalStorageAvailable = storageAvailable("localStorage");
var isSessionStorageAvailable = storageAvailable("sessionStorage");
// set theme
let theme = "light";
if (isLocalStorageAvailable) {
var torusTheme = localStorage.getItem("torus-theme");
if (torusTheme) {
theme = torusTheme.split("-")[0];
}
}

if (theme === "dark") {
document.querySelector("body").style.backgroundColor = "#24252A";
}
var bc;
var broadcastChannelOptions = {
// type: 'localstorage', // (optional) enforce a type, oneOf['native', 'idb', 'localstorage', 'node'
webWorkerSupport: false, // (optional) set this to false if you know that your channel will never be used in a WebWorker (increase performance)
};
var instanceParams = {};
var preopenInstanceId = new URL(window.location.href).searchParams.get("preopenInstanceId");
if (!preopenInstanceId) {
document.getElementById("message").style.visibility = "visible";
// in general oauth redirect
try {
var url = new URL(location.href);
var hash = url.hash.substr(1);
var hashParams = {};
if (hash) {
hashParams = hash.split("&").reduce(function (result, item) {
var parts = item.split("=");
result[parts[0]] = parts[1];
return result;
}, {});
}
var queryParams = {};
for (var key of url.searchParams.keys()) {
queryParams[key] = url.searchParams.get(key);
}
var error = "";
try {
if (Object.keys(hashParams).length > 0 && hashParams.state) {
instanceParams = JSON.parse(window.atob(decodeURIComponent(decodeURIComponent(hashParams.state)))) || {};
if (hashParams.error) error = hashParams.error;
} else if (Object.keys(queryParams).length > 0 && queryParams.state) {
instanceParams = JSON.parse(window.atob(decodeURIComponent(decodeURIComponent(queryParams.state)))) || {};
if (queryParams.error) error = queryParams.error;
}
} catch (e) {
console.error(e);
}
if (instanceParams.redirectToOpener) {
// communicate to window.opener
window.opener.postMessage(
{
channel: "redirect_channel_" + instanceParams.instanceId,
data: {
instanceParams: instanceParams,
hashParams: hashParams,
queryParams: queryParams,
},
error: error,
},
"http://localhost:3000"
);
} else {
// communicate via broadcast channel
bc = new broadcastChannelLib.BroadcastChannel("redirect_channel_" + instanceParams.instanceId, broadcastChannelOptions);
bc.addEventListener("message", function (ev) {
if (ev.success) {
bc.close();
console.log("posted", {
queryParams,
instanceParams,
hashParams,
});
} else {
window.close();
showCloseText();
}
});
bc.postMessage({
data: {
instanceParams: instanceParams,
hashParams: hashParams,
queryParams: queryParams,
},
error: error,
}).then(function () {
setTimeout(function () {
window.location.href = url.origin + location.search + location.hash;
}, 5000);
});
}
} catch (err) {
console.error(err, "service worker error in redirect");
bc && bc.close();
window.close();
showCloseText();
}
} else {
// in preopen, awaiting redirect
try {
bc = new broadcastChannelLib.BroadcastChannel("preopen_channel_" + preopenInstanceId, broadcastChannelOptions);
bc.onmessage = function (ev) {
var { preopenInstanceId: oldId, payload, message } = ev.data;
if (oldId === preopenInstanceId && payload && payload.url) {
window.location.href = payload.url;
} else if (oldId === preopenInstanceId && message === "setup_complete") {
bc.postMessage({
data: {
preopenInstanceId: preopenInstanceId,
message: "popup_loaded",
},
});
}
if (ev.error && ev.error !== "") {
console.error(ev.error);
bc.close();
}
};
} catch (err) {
console.error(err, "service worker error in preopen");
bc && bc.close();
window.close();
showCloseText();
}
}
</script>
</body>
</html>

${""}
`,
],
{ type: "text/html" }
)
)
);
}
} catch (error) {
console.log("Hello");
console.error(error);
}
});

Redirect Mode

If you are using the redirect mode, don't have to use the service worker or redirect.html file. You can get login results by calling the init() function on the redirected page mount.

For example, if baseUrl is https://your-domain.com and redirectPathName is auth then the user will be redirected to the https://your-domain.com/auth page after logging in where you can get login result by calling init() function on redirected page mount.

Log In with JWT (BYOA)

loginWithJWT(idTokenLoginParams: IdTokenLoginParams): Promise<void>;

VariableTypeDescriptionMandatory
idTokenLoginParamsobjectLogin ParametersYes

IdTokenLoginParams

ParameterTypeMandatoryDescription
verifierstringYesName of the verifier created on Web3Auth Dashboard. In the case of Aggregate Verifier, the name of the top-level aggregate verifier.
verifierIdstringYesUnique Identifier for the User. The verifier identifier field is set for the verifier/sub verifier. E.g. "sub" field in your JWT ID Token.
idTokenstringYesThe idToken received from the Auth Provider.
subVerifier?stringNoName of the sub verifier in case of aggregate verifier setup. This field is mandatory in the case of an aggregate verifier.
extraVerifierParams?WebAuthnExtraParamsNoExtra verifier params in case of a WebAuthn verifier type.
additionalParams?ExtraParamsNoAny additional parameter (key-value pair) you'd like to pass to the login function.

Usage

General Verifier

import { Web3AuthMPCCoreKit, idTokenLoginParams } from "@web3auth/mpc-core-kit";

const loginRes = await signInWithGoogle();
const idToken = await loginRes.user.getIdToken(true);
const parsedToken = parseToken(idToken);

const idTokenLoginParams = {
verifier: "w3a-firebase-demo",
verifierId: parsedToken.email,
idToken,
} as IdTokenLoginParams;

await coreKitInstance.loginWithJWT(idTokenLoginParams);

Aggregate Verifier

import { Web3AuthMPCCoreKit, idTokenLoginParams } from "@web3auth/mpc-core-kit";

const loginRes = await signInWithGoogle();
const idToken = await loginRes.user.getIdToken(true);
const parsedToken = parseToken(idToken);

const idTokenLoginParams = {
verifier: "aggregate-sapphire"
subVerifier: "w3a-google",
verifierId: parsedToken.email,
idToken,
} as IdTokenLoginParams;

await coreKitInstance.loginWithJWT(idTokenLoginParams);

Logging out the User

logout(): Promise<void>;

Disconnect the user's connected wallet/ provider and log them out of the Web3Auth MPC Core Kit SDK.

Usage

await coreKitInstance.logout();