Skip to content

Commit

Permalink
[EXC-22] identity login examples (#1992)
Browse files Browse the repository at this point in the history
  • Loading branch information
andrew-yangy authored Jul 22, 2024
1 parent 0c11a50 commit 07b182c
Show file tree
Hide file tree
Showing 17 changed files with 9,689 additions and 0 deletions.
2 changes: 2 additions & 0 deletions examples/passport/identity/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
NEXT_PUBLIC_PUBLISHABLE_KEY=
NEXT_PUBLIC_CLIENT_ID=
3 changes: 3 additions & 0 deletions examples/passport/identity/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"extends": "next/core-web-vitals"
}
36 changes: 36 additions & 0 deletions examples/passport/identity/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.js
.yarn/install-state.gz

# testing
/coverage

# next.js
/.next/
/out/

# production
/build

# misc
.DS_Store
*.pem

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# local env files
.env*.local

# vercel
.vercel

# typescript
*.tsbuildinfo
next-env.d.ts
22 changes: 22 additions & 0 deletions examples/passport/identity/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
This is an example of [Setup Passport Identity](https://docs.immutable.com/products/zkEVM/passport/setup).

## Getting Started

First, run the development server:

```bash
npm run dev
# or
yarn dev
# or
pnpm dev
# or
bun dev
```

Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.

## Required Environment Variables

- NEXT_PUBLIC_PUBLISHABLE_KEY // replace with your publishable API key from Hub
- NEXT_PUBLIC_CLIENT_ID // replace with your client ID from Hub
4 changes: 4 additions & 0 deletions examples/passport/identity/next.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/** @type {import('next').NextConfig} */
const nextConfig = {};

export default nextConfig;
28 changes: 28 additions & 0 deletions examples/passport/identity/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"name": "identity",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint"
},
"dependencies": {
"next": "14.2.5",
"react": "^18",
"react-dom": "^18"
},
"devDependencies": {
"@imtbl/sdk": "latest",
"@types/node": "^20",
"@types/react": "^18",
"@types/react-dom": "^18",
"autoprefixer": "^10.4.19",
"eslint": "^8",
"eslint-config-next": "14.2.5",
"postcss": "^8.4.39",
"tailwindcss": "^3.4.6",
"typescript": "^5"
}
}
8 changes: 8 additions & 0 deletions examples/passport/identity/postcss.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/** @type {import('postcss-load-config').Config} */
const config = {
plugins: {
tailwindcss: {},
},
};

export default config;
3 changes: 3 additions & 0 deletions examples/passport/identity/src/app/globals.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
24 changes: 24 additions & 0 deletions examples/passport/identity/src/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import type { Metadata } from "next";
import { Inter } from "next/font/google";
import { PassportProvider } from "@/context/passport";
import { ReactNode } from "react";
import "./globals.css";
const inter = Inter({ subsets: ["latin"] });

export const metadata: Metadata = {
title: "Passport Identity example",
};

export default function RootLayout({
children,
}: Readonly<{
children: ReactNode;
}>) {
return (
<html lang="en">
<body className={inter.className}>
<PassportProvider>{children}</PassportProvider>
</body>
</html>
);
}
13 changes: 13 additions & 0 deletions examples/passport/identity/src/app/logout/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
'use client';

import { useEffect } from 'react';
import { useRouter } from 'next/navigation';

export default function Page() {
const { push } = useRouter();

useEffect(() => {
push('/');
}, [push]);
return <p />;
};
40 changes: 40 additions & 0 deletions examples/passport/identity/src/app/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
'use client';

import { usePassport } from "@/context/passport";

export default function Home() {
const {
login,
logout,
logoutSilent,
loginWithoutWallet,
loginWithEthersjs,
getIdToken,
getAccessToken,
} = usePassport();

return (<>
<div className="flex flex-col items-center justify-center min-h-screen p-8">
<h1 className="text-3xl font-bold mb-8">Passport Identity Examples</h1>
<div className="flex flex-wrap space-x-4">
<button className="bg-black text-white py-2 px-4 rounded hover:bg-gray-800" onClick={login}>Login</button>
<button className="bg-black text-white py-2 px-4 rounded hover:bg-gray-800" onClick={logout}>Logout in Redirect
mode
</button>
<button className="bg-black text-white py-2 px-4 rounded hover:bg-gray-800" onClick={logoutSilent}>Logout in
Silent mode
</button>
<button className="bg-black text-white py-2 px-4 rounded hover:bg-gray-800" onClick={loginWithoutWallet}>Login
Without Wallet
</button>
<button className="bg-black text-white py-2 px-4 rounded hover:bg-gray-800" onClick={loginWithEthersjs}>Login
With Ethers.js
</button>
<button className="bg-black text-white py-2 px-4 rounded hover:bg-gray-800" onClick={getIdToken}>Get ID Token
</button>
<button className="bg-black text-white py-2 px-4 rounded hover:bg-gray-800" onClick={getAccessToken}>Get Access Token
</button>
</div>
</div>
</>);
}
18 changes: 18 additions & 0 deletions examples/passport/identity/src/app/redirect/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
'use client';

import { usePassport } from "@/context/passport";
import { useEffect } from "react";

export default function Redirect() {
const { passportInstance } = usePassport();

useEffect(() => {
if(passportInstance) {
// #doc passport-login-callback
passportInstance.loginCallback();
// #enddoc passport-login-callback
}
}, [passportInstance]);

return (<h1>Redirecting...</h1>);
}
18 changes: 18 additions & 0 deletions examples/passport/identity/src/app/silent-logout/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
'use client';

import { useEffect } from 'react';
import { usePassport } from "@/context/passport";

export default function Page() {
const { passportSilentInstance } = usePassport();

useEffect(() => {
if(passportSilentInstance) {
const passport = passportSilentInstance;
// #doc passport-silent-logout-callback
passport.loginCallback();
// #enddoc passport-silent-logout-callback
}
}, [passportSilentInstance]);
return <p />;
};
134 changes: 134 additions & 0 deletions examples/passport/identity/src/context/passport.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
'use client';

import { createContext, ReactNode, useCallback, useContext } from "react";
import { config, passport } from "@imtbl/sdk";
import { ethers } from "ethers";

type PassportContextType = {
passportInstance?: passport.Passport,
passportSilentInstance?: passport.Passport,
login?: () => void,
logout?: () => void,
logoutSilent?: () => void,
loginWithoutWallet?: () => void,
loginWithEthersjs?: () => void,
getIdToken?: () => void,
getAccessToken?: () => void,
}

const PassportContext = createContext<PassportContextType>({});

export const PassportProvider = ({children}: {
children: ReactNode;
}) => {

const passportInstance = new passport.Passport({
baseConfig: {
environment: config.Environment.SANDBOX, // or config.Environment.SANDBOX
publishableKey: process.env.NEXT_PUBLIC_PUBLISHABLE_KEY || '<YOUR_PUBLISHABLE_KEY>', // replace with your publishable API key from Hub
},
clientId: process.env.NEXT_PUBLIC_CLIENT_ID || '<YOUR_CLIENT_ID>', // replace with your client ID from Hub
redirectUri: 'http://localhost:3000/redirect', // replace with one of your redirect URIs from Hub
logoutRedirectUri: 'http://localhost:3000/logout', // replace with one of your logout URIs from Hub
audience: 'platform_api',
scope: 'openid offline_access email transact',
popupOverlayOptions: {
disableGenericPopupOverlay: false, // Set to true to disable the generic pop-up overlay
disableBlockedPopupOverlay: false, // Set to true to disable the blocked pop-up overlay
}
});

const passportSilentInstance = new passport.Passport({
baseConfig: {
environment: config.Environment.SANDBOX, // or config.Environment.SANDBOX
publishableKey: process.env.NEXT_PUBLIC_PUBLISHABLE_KEY || '<YOUR_PUBLISHABLE_KEY>', // replace with your publishable API key from Hub
},
clientId: process.env.NEXT_PUBLIC_CLIENT_ID || '<YOUR_CLIENT_ID>', // replace with your client ID from Hub
redirectUri: 'http://localhost:3000/redirect', // replace with one of your redirect URIs from Hub
logoutRedirectUri: 'http://localhost:3000/silent-logout', // replace with one of your logout URIs from Hub
logoutMode: 'silent',
audience: 'platform_api',
scope: 'openid offline_access email transact',
});

const login = useCallback(async () => {
if (!passportInstance) return;
// #doc passport-evm-login
const provider = passportInstance.connectEvm();
const accounts = await provider.request({method: "eth_requestAccounts"});
// #enddoc passport-evm-login
window.alert('accounts: ' + accounts);
}, [passportInstance])

const logout = useCallback(async () => {
if (!passportInstance) return;
// #doc passport-logout
await passportInstance.logout();
// #enddoc passport-logout
}, [passportInstance])

const logoutSilent = useCallback(async () => {
if (!passportSilentInstance) return;
const passport = passportSilentInstance;
// #doc passport-silent-logout
await passport.logout();
// #enddoc passport-silent-logout
}, [passportSilentInstance])

const loginWithoutWallet = useCallback(async () => {
if (!passportInstance) return;
// #doc passport-login-without-wallet
const profile: passport.UserProfile | null = await passportInstance.login();
// #enddoc passport-login-without-wallet
window.alert('profile: ' + JSON.stringify(profile));
}, [passportInstance])

const loginWithEthersjs = useCallback(async () => {
if (!passportInstance) return;
// #doc passport-login-with-ethersjs
const passportProvider = passportInstance.connectEvm();

const web3Provider = new ethers.providers.Web3Provider(passportProvider);

const accounts = await web3Provider.send("eth_requestAccounts", []);
// #enddoc passport-login-with-ethersjs

const signer = web3Provider.getSigner();

window.alert('accounts: ' + accounts + ' signer: ' + JSON.stringify(signer));
}, [passportInstance])

const getIdToken = useCallback(async () => {
if (!passportInstance) return;
// #doc passport-get-id-token
const idToken = await passportInstance.getIdToken();
// #enddoc passport-get-id-token
window.alert('idToken: ' + idToken);
}, [passportInstance])

const getAccessToken = useCallback(async () => {
if (!passportInstance) return;
// #doc passport-get-access-token
const accessToken = await passportInstance.getAccessToken();
// #enddoc passport-get-access-token
window.alert('accessToken: ' + accessToken);
}, [passportInstance])

return (
<PassportContext.Provider value={{
passportInstance,
passportSilentInstance,
login,
logout,
logoutSilent,
loginWithoutWallet,
loginWithEthersjs,
getIdToken,
getAccessToken
}}>
{children}
</PassportContext.Provider>
)
}

export const usePassport = () => useContext(PassportContext);
20 changes: 20 additions & 0 deletions examples/passport/identity/tailwind.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import type { Config } from "tailwindcss";

const config: Config = {
content: [
"./src/pages/**/*.{js,ts,jsx,tsx,mdx}",
"./src/components/**/*.{js,ts,jsx,tsx,mdx}",
"./src/app/**/*.{js,ts,jsx,tsx,mdx}",
],
theme: {
extend: {
backgroundImage: {
"gradient-radial": "radial-gradient(var(--tw-gradient-stops))",
"gradient-conic":
"conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))",
},
},
},
plugins: [],
};
export default config;
Loading

0 comments on commit 07b182c

Please sign in to comment.