Skip to content

Commit

Permalink
feat(SocialLogins.tsx): Finish login with Apple implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
KingRainbow44 committed Jul 31, 2024
1 parent e382cda commit 8a6d405
Show file tree
Hide file tree
Showing 5 changed files with 64 additions and 9 deletions.
Binary file modified bun.lockb
Binary file not shown.
1 change: 0 additions & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
<meta content="https://seikimo.moe/seikimo.png" property="og:image" />
<meta content="#52FADB" name="theme-color" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<script src="https://appleid.cdn-apple.com/appleauth/static/jsapi/appleid/1/en_US/appleid.auth.js"></script>
<link rel="icon" href="/icon.png">
<title>seiKiMo Inc.</title>

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"axios": "^1.4.0",
"highlight.js": "^11.8.0",
"react": "^18.2.0",
"react-apple-login": "^1.1.6",
"react-apple-signin-auth": "^1.1.0",
"react-dom": "^18.2.0",
"react-icons": "^4.10.1",
"react-router-dom": "^6.8.1",
Expand Down
14 changes: 14 additions & 0 deletions src/backend/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,20 @@ export type AccountCredentials = {
token: string;
};

export type AppleLoginResponse = {
authorization: {
code: string;
id_token: string;
};
user?: {
name: {
firstName: string;
lastName: string;
};
email: string;
};
};

export type Profile = {
icon: string;
displayName: string;
Expand Down
56 changes: 49 additions & 7 deletions src/ui/components/SocialLogins.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import React from "react";

import AppleLogin from "react-apple-login";
import AppleLogin from "react-apple-signin-auth";

import { ReactComponent as GoogleIcon } from "@icons/google.svg";
import { ReactComponent as DiscordIcon } from "@icons/discord.svg";

import { expectedOrigin, newCall } from "@app/index";
import { getRedirectUrl, handoffCode } from "@utils/login";
import type { AppleLoginResponse } from "@backend/types";

import "@css/Account.scss";

Expand All @@ -28,6 +29,14 @@ function socialLogin(route: string, name: string): void {

// Focus the window.
authWindow.focus();

waitForLogin();
}

/**
* Adds an event listener which waits for a login response.
*/
function waitForLogin() {
// Add a message handler.
window.addEventListener("message", (event) => {
// Check the event origin.
Expand All @@ -48,6 +57,34 @@ function socialLogin(route: string, name: string): void {
});
}

/**
* Invoked when the completion of an Apple login takes place.
*
* @param appleResponse The response from the Apple login.
*/
async function onAppleLogin(appleResponse: AppleLoginResponse) {
const { user, authorization: { code } } = appleResponse;

// Check if the user was specified.
const userEncoded = user == null ? "none" : btoa(JSON.stringify(user));

// Exchange with the backend server for a token.
const response = await fetch(newCall(`account/login/apple?code=${code}&user=${userEncoded}`));
if (response.status != 200) {
alert("Failed to authenticate with Apple.");
return;
}

// Store the credentials in the local storage.
const credentials = await response.text();
localStorage.setItem("credentials", credentials);

// Encode the credentials.
const encoded = btoa(credentials);
// Redirect to the redirect URL.
window.location.replace(getRedirectUrl(handoffCode() ? encoded : undefined));
}

interface IButtonProps {
gap: number;
service: string;
Expand Down Expand Up @@ -91,19 +128,24 @@ function SocialLogins() {
</Button>

<AppleLogin
scope={"name email"}
render={({ onClick }) => (
authOptions={{
clientId: import.meta.env.VITE_APPLE_CLIENT_ID ?? "",
redirectURI: import.meta.env.VITE_APPLE_REDIRECT_URI ?? "",
scope: "email name",
usePopup: true
}}
render={(props: any) => (
<Button
{...props}
gap={8}
service={"Apple"}
onClick={onClick}
>
<img src={"/apple.png"} alt={"Apple Icon"} className={"w-[24px]"} />
</Button>
)}
usePopup={true}
clientId={import.meta.env.VITE_APPLE_CLIENT_ID ?? ""}
redirectURI={import.meta.env.VITE_APPLE_REDIRECT_URI ?? ""}
uiType={"dark"}
onSuccess={onAppleLogin}
onError={(error: any) => alert(error)}
/>
</div>
);
Expand Down

0 comments on commit 8a6d405

Please sign in to comment.