Day 8 - Secure 🔐 Login with AIOHA & LocalStorage Magic 🧙

Words
477
Reading
3 min
1y
Listen to this post
~3 min

📣 Hello Hive Community Members!


Welcome back to my wild ReactJS learning ride 🎢 — and guess what? We’re already on Day 8! If you've missed previous episodes, don't worry. Grab some popcorn 🍿 and catch up below:


📖 ReactJS Journey So Far


🚀 What’s New in Day 8?

In this episode, I went full-on security ninja. 🥷 Here's what I implemented:

  • 🔐 Login API with aioha@aioha & distriator combo
  • 📦 Storing user data securely in localStorage using AES encryption & base64 encoding
  • ✅ Upsert logic for managing multiple Hive logins

🧠 Data Modeling Like a Boss

📁 Folder: src/types/LoginApiRequestResponse.tsx

export interface LoginRequestDTO {
  challenge: string;
  proof: string;
  pubkey: string;
  username: string;
}

export interface LoginSuccessResponseDTO {
  token: string;
  type: string;
}

export interface LocalStorageUserDTO {
  token: string;
  type: string;
  challenge: string;
  proof: string;
  pubkey: string;
  username: string;
}

export interface LoginErrorResponseDTO {
  error: string;
}

💾 Encrypting User Data in LocalStorage

localstorage image reference

📁 File: src/utils/LocalStorageUtils.tsx
Let’s bring in the secret scrolls of utility magic! 🧙

🔐 Base64 Helper Spells

function toBase64(str: string): string {
  return typeof window !== "undefined"
    ? window.btoa(unescape(encodeURIComponent(str)))
    : Buffer.from(str, "utf-8").toString("base64");
}

function fromBase64(b64: string): string {
  return typeof window !== "undefined"
    ? decodeURIComponent(escape(window.atob(b64)))
    : Buffer.from(b64, "base64").toString("utf-8");
}

📥 Retrieve Users from LocalStorage (aka Decrypt Scroll)

export function getLoggedInUsers(): LocalStorageUserDTO[] {
  const apiKey = import.meta.env.VITE_LOCAL_KEY;
  const data = localStorage.getItem("logged-in-users") || "";
  const decrypteText = CryptoJS.AES.decrypt(data, apiKey).toString(
    CryptoJS.enc.Utf8
  );
  if (!data) return [];
  try {
    const jsonStr = fromBase64(decrypteText);
    return JSON.parse(jsonStr);
  } catch (e) {
    console.error("Failed to decode/parse localStorage ", e);
    return [];
  }
}

📝 Steps:

  • Get 🔐 key from .env
  • Decrypt → decode → parse → return!

📝 Store/Update New Logged-In Users (Avengers-like registry 🦸)

export function setLoggedInUsers(users: LocalStorageUserDTO[]): void {
  try {
    const apiKey = import.meta.env.VITE_DEKEY;
    const jsonStr = JSON.stringify(users);
    const base64Str = toBase64(jsonStr);
    const encryptedText = CryptoJS.AES.encrypt(base64Str, apiKey).toString();
    localStorage.setItem("logged-in-users", encryptedText);
  } catch (e) {
    console.error("Failed to encode/set localStorage ", e);
  }
}

🔄 Save/Update User Info (like a React-powered CRM 😎)

export function saveOrUpdateUser(newUser: LocalStorageUserDTO): void {
  const users = getLoggedInUsers();
  const idx = users.findIndex((user) => user.username === newUser.username);
  if (idx !== -1) {
    users[idx] = newUser;
  } else {
    users.push(newUser);
  }
  setLoggedInUsers(users);
}

🙅‍♂️ No remove logic yet — coming with future logout feature. Stay tuned!


🔌 Calling the Login API – FTW!

📁 File: src/api/LoginApi.tsx

Here’s how the server handshake looks:

export const loginApi = async (challenge, proof, pubkey, username): Promise<null | string> => {
  try {
    const rqst: LoginRequestDTO = { challenge, proof, pubkey, username };
    const response = await fetch("https://beta-api.distriator.com/login", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(rqst),
    });

    if (!response.ok) {
      const errorBody: LoginErrorResponseDTO = await response.json();
      console.error("Login failed:", errorBody);
      return `Error - ${errorBody.error}`;
    }

    const success: LoginSuccessResponseDTO = await response.json();
    const updatedUser: LocalStorageUserDTO = { ...rqst, token: success.token, type: success.type };
    saveOrUpdateUser(updatedUser);
    return null;

  } catch (error) {
    console.error("Network error:", error);
    return `Network error - ${error.message}`;
  }
};

🔥 Boom! Now you're securely logged in and your data is sealed like Wakanda tech! 🛡️


🤝 AIOHA + Distriator Login Combo 💪

📁 File: src/components/HiveUserAvatarButton.tsx

We've glued it all together using @aioha/react-ui. 🧩

<AiohaModal
  displayed={modalDisplayed}
  loginOptions={{
    msg: proof,
    keyType: KeyTypes.Posting,
  }}
  onLogin={performLogin}
  onClose={setModalDisplayed}
/>

And here’s the magic performLogin function:

async function performLogin(result: LoginResult) {
  if (result.success) {
    const loginResult = await loginApi(result.result, proof, result.publicKey || "none", result.username);
    if (loginResult == null) {
      console.log("🎉 Logged in successfully!");
    } else {
      console.error(`Login failed: ${loginResult}`);
    }
  } else {
    console.error(result.error || "Something went wrong");
  }
}

🎯 Wrapping Up

This was a deep dive into login flows, secure data handling & functional integration of blockchain login workflows! 🧩

That's it for now, folks! Thank you so much for reading my post. 💙

More power to the Hive Blockchain 🐝
More power to all our community members 🙌
Until next time, Happy Coding! 💻✨


📝 Final Note


🚀 My Contributions to ♦️ Hive Ecosystem

ContributionToHiveEcosystem
Hive Witness NodeHive API Node (in progress)3Speak Video Encoder Node Operator (highest number of nodes)3Speak Mobile App Developer
3Speak Podcast App Developer3Speak Shorts App Developer3Speak Support & Maintenance TeamDistriator Developer
CheckinWithXYZHive InboxHiFindHive Donate App
Contributed to HiveAuth Mobile AppEcency ↔ 3Speak IntegrationEcency ↔ InLeo IntegrationEcency ↔ Actifit Integration
Hive Stats AppVote for Witness AppHiveFlutterKitNew 3Speak App

🙌 Support Back

❤️ Appreciate my work? Consider supporting threespeak@threespeak & sagarkothari88@sagarkothari88! ❤️

VoteForWitness
sagarkothari88sagarkothari88@sagarkothari88
threespeakthreespeak@threespeak

Day 8 - Secure 🔐 Login with AIOHA & LocalStorage Magic 🧙 | Ecency