Skip to content

Commit

Permalink
✨ Added Metamask Provider
Browse files Browse the repository at this point in the history
  • Loading branch information
osadavc committed May 16, 2022
1 parent ce393e6 commit c937192
Show file tree
Hide file tree
Showing 20 changed files with 867 additions and 24 deletions.
1 change: 1 addition & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"astrojs",
"behaviour",
"builtins",
"Inpage",
"nanostores",
"pkce",
"preact",
Expand Down
8 changes: 4 additions & 4 deletions apps/dev/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@
"react-dom": "^18.0.0"
},
"dependencies": {
"@astro-auth/client": "1.0.1",
"@astro-auth/core": "1.0.3",
"@astro-auth/providers": "1.0.1",
"@astro-auth/ui": "1.0.1"
"@astro-auth/client": "1.0.3",
"@astro-auth/core": "1.0.11",
"@astro-auth/providers": "1.0.5",
"@astro-auth/ui": "1.0.3"
}
}
3 changes: 3 additions & 0 deletions apps/dev/src/components/IntroSection/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
DiscordButton,
TwitterButton,
GithubButton,
MetamaskButton,
} from "@astro-auth/ui";
import { signIn, signOut, ReactStateStore } from "@astro-auth/client";
import styles from "./index.module.css";
Expand Down Expand Up @@ -67,6 +68,8 @@ const IntroSection: FC<IntroSectionProps> = ({ isSignIn = false, user }) => {
>
LOGIN
</button>

<MetamaskButton />
</div>
)}

Expand Down
15 changes: 12 additions & 3 deletions apps/dev/src/pages/api/auth/[...astroauth].ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
CredentialProvider,
TwitterProvider,
GithubProvider,
MetamaskProvider,
} from "@astro-auth/providers";

export const all = AstroAuth({
Expand Down Expand Up @@ -35,9 +36,17 @@ export const all = AstroAuth({
return null;
},
}),
MetamaskProvider({
authorize: async (properties) => properties,
signMessage: "Hello From Astro Auth",
}),
],
hooks: {
jwt: (user) => {
jwt: async (user) => {
if (user.provider == "metamask") {
return user;
}

return {
accessToken: user.access_token,
refreshToken: user.refresh_token,
Expand All @@ -47,10 +56,10 @@ export const all = AstroAuth({
},
};
},
signIn: () => {
signIn: async () => {
return true;
},
redirectError: (error) => {
redirectError: async (error) => {
console.log(error.message);
return "/";
},
Expand Down
4 changes: 3 additions & 1 deletion packages/astro-auth-client/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@astro-auth/client",
"version": "1.0.2",
"version": "1.0.3",
"main": "dist/index.js",
"type": "module",
"description": "The client package of the Astro Auth library",
Expand Down Expand Up @@ -35,7 +35,9 @@
"react-dom": "^18.0.0"
},
"dependencies": {
"@metamask/providers": "^8.1.1",
"@nanostores/react": "^0.2.0",
"ethers": "^5.6.6",
"nanostores": "^0.5.12",
"redaxios": "^0.4.1"
}
Expand Down
39 changes: 38 additions & 1 deletion packages/astro-auth-client/src/signIn/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
import { Providers } from "@astro-auth/types";
import axios from "redaxios";
import { MetaMaskInpageProvider } from "@metamask/providers";
import { ethers } from "ethers";

declare global {
interface Window {
ethereum: MetaMaskInpageProvider;
}
}

const signIn = async ({
provider,
Expand All @@ -16,11 +24,40 @@ const signIn = async ({
);
}

let metamaskInfo: {
address?: string;
signature?: string;
} = {};

if (provider == "metamask") {
if (!window.ethereum) {
return {
error: "Metamask is not installed",
};
}

await window.ethereum.request({
method: "eth_requestAccounts",
});
const provider = new ethers.providers.Web3Provider(window.ethereum as any);
const signer = provider.getSigner();

const { data } = await axios.get("api/auth/sign-message");

const signature = await signer.signMessage(data.message);
const address = await signer.getAddress();

metamaskInfo = {
address,
signature,
};
}

const { data } = await axios
.post("/api/auth/signin", {
provider,
callback: callbackURL ?? location.href,
login,
login: login ?? metamaskInfo,
})
.catch((err) => err);

Expand Down
3 changes: 2 additions & 1 deletion packages/astro-auth-core/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@astro-auth/core",
"version": "1.0.10",
"version": "1.0.11",
"description": "The core package of the Astro Auth library",
"main": "dist/index.js",
"type": "module",
Expand Down Expand Up @@ -36,6 +36,7 @@
},
"dependencies": {
"@astro-auth/types": "1.0.1",
"ethers": "^5.6.6",
"jsonwebtoken": "^8.5.1",
"openid-client": "^5.1.5"
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
const getMessageToSign = (message: string) => {
return message ?? "Welcome To Astro Auth";
};

export default getMessageToSign;
44 changes: 43 additions & 1 deletion packages/astro-auth-core/src/AstroAuth/handlers/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import { MetamaskUserOptions } from "@astro-auth/types";
import { AstroAuthParams } from "..";
import getURLSlash from "../../utils/getURLSlash";
import parseCookie from "../../utils/parseCookieString";
import getMessageToSign from "./getMessageToSign";
import getServerUser from "./getServerUser";
import OAuthCallback from "./oauthCallback";
import signIn from "./signIn";
Expand Down Expand Up @@ -39,17 +42,56 @@ const astroAuthHandler = async (
case "user": {
return getServerUser(request, config.hooks?.account);
}
case "sign-message": {
const metamaskProvider = config.authProviders?.find(
(provider) => provider.id == "metamask"
);

if (!metamaskProvider) {
if (config.hooks?.redirectError) {
const redirectURL = await config.hooks.redirectError(
new Error("Metamask provider is not configured")
);

return {
status: 307,
headers: {
"Content-Type": undefined,
Location: `${getURLSlash(
redirectURL
)}/?error=Metamask provider is not configured`,
},
};
}

throw new Error("Metamask is not configured");
}

return {
status: 200,
body: {
message: getMessageToSign(
(metamaskProvider?.options as MetamaskUserOptions).signMessage
),
},
};
}
default: {
if (url.startsWith("oauth")) {
const oauthConfig = config.authProviders?.find(
(provider) => provider.id === url.split("/")[1]
);
const code = new URL(request.url).searchParams.get("code");
if (oauthConfig?.type == "credential") {

if (
oauthConfig?.type == "credential" ||
oauthConfig?.type == "metamask"
) {
return {
status: 500,
};
}

const { user, encodedJWT } = await OAuthCallback(
request,
oauthConfig,
Expand Down
55 changes: 53 additions & 2 deletions packages/astro-auth-core/src/AstroAuth/handlers/signIn.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
import { OAuthConfig, CredentialConfig } from "@astro-auth/types";
import {
OAuthConfig,
CredentialConfig,
MetamaskConfig,
} from "@astro-auth/types";
import openIdClient from "../../lib/oauth/client";
import jwt from "jsonwebtoken";
import { getPKCE } from "../../lib/oauth/pkceUtils";
import { getState } from "../../lib/oauth/stateUtils";
import getURLSlash from "../../utils/getURLSlash";
import { ethers } from "ethers";
import getMessageToSign from "./getMessageToSign";

const signIn = async (
request: Request,
callback: string,
config?: OAuthConfig | CredentialConfig,
config?: OAuthConfig | CredentialConfig | MetamaskConfig,
generateJWT?: (user: any) => any,
redirectError?: ((error: Error) => Promise<string>) | undefined
) => {
Expand Down Expand Up @@ -61,6 +67,51 @@ const signIn = async (
};
}

if (config?.type == "metamask") {
const loginDetails = (await request.json().catch(() => {})).login;

const signatureAddress = await ethers.utils.verifyMessage(
getMessageToSign(config.options.signMessage),
loginDetails.signature
);

const user = await config.options.authorize(loginDetails);

if (!user || signatureAddress != user.address) {
return {
status: 401,
headers: {
"Content-Type": undefined,
"Set-Cookie":
"__astroauth__session__=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT",
},
body: {
redirect: "/?error=Wrong Credentials",
},
};
}

const generatedData = generateJWT
? await generateJWT({ ...user, provider: config.id })
: user;

const encodedJWT = await jwt.sign(
generatedData,
import.meta.env.ASTROAUTH_SECRET
);

return {
status: 200,
headers: {
"Content-Type": undefined,
"Set-Cookie": `__astroauth__session__=${encodedJWT}; path=/; HttpOnly; Path=/;`,
},
body: {
redirect: callback,
},
};
}

if (!config) {
if (redirectError) {
const redirectURL = await redirectError(
Expand Down
8 changes: 6 additions & 2 deletions packages/astro-auth-core/src/AstroAuth/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import { OAuthConfig, CredentialConfig } from "@astro-auth/types";
import {
OAuthConfig,
CredentialConfig,
MetamaskConfig,
} from "@astro-auth/types";
import astroAuthHandler from "./handlers/index";

export interface AstroAuthParams {
authProviders?: (OAuthConfig | CredentialConfig)[];
authProviders?: (OAuthConfig | CredentialConfig | MetamaskConfig)[];
hooks?: {
jwt?: (user: any) => Promise<any>;
signIn?: (user: any) => Promise<boolean | string>;
Expand Down
2 changes: 1 addition & 1 deletion packages/astro-auth-providers/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@astro-auth/providers",
"version": "1.0.4",
"version": "1.0.5",
"main": "dist/index.js",
"type": "module",
"description": "The providers package of the Astro Auth library",
Expand Down
2 changes: 2 additions & 0 deletions packages/astro-auth-providers/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import SpotifyProvider from "./providers/SpotifyProvider";
import ZoomProvider from "./providers/ZoomProvider";

import CredentialProvider from "./providers/CredentialProvider";
import MetamaskProvider from "./providers/MetamaskProvider";

export {
GoogleProvider,
Expand All @@ -19,4 +20,5 @@ export {
SpotifyProvider,
ZoomProvider,
CredentialProvider,
MetamaskProvider,
};
11 changes: 11 additions & 0 deletions packages/astro-auth-providers/src/providers/MetamaskProvider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { MetamaskConfig, MetamaskUserOptions } from "@astro-auth/types";

const CredentialProvider = (options: MetamaskUserOptions): MetamaskConfig => {
return {
id: "metamask",
type: "metamask",
options,
};
};

export default CredentialProvider;
2 changes: 1 addition & 1 deletion packages/astro-auth-types/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@astro-auth/types",
"version": "1.0.1",
"version": "1.0.2",
"main": "src/index.ts",
"author": "Osada Vidath <[email protected]>",
"license": "MIT",
Expand Down
Loading

0 comments on commit c937192

Please sign in to comment.