Chapter 2: Perfectly Integrating LIFF with Line Login in React

In the previous chapter, we obtained the sacred LIFF ID. Now we'll return to our React + Vite project to install Line's SDK.
Master this step, and your web app will possess the "login-on-open" black magic technology.

1. Install the @line/liff Package

Run in terminal:

npm install @line/liff

2. Create a LIFF Initialization Hook (useLiff.ts)

Don't scatter LIFF logic across components! We'll write a custom Hook to centrally manage Line's login state.

// src/hooks/useLiff.ts
import { useEffect, useState } from 'react';
import liff from '@line/liff';

export function useLiff() {
  const [profile, setProfile] = useState<any>(null);
  const [error, setError] = useState<string | null>(null);
  const [isReady, setIsReady] = useState(false);

  useEffect(() => {
    // Insert the LIFF ID you obtained in the previous chapter here
    liff.init({ liffId: import.meta.env.VITE_LIFF_ID })
      .then(() => {
        setIsReady(true);
        // Check if opened inside Line or already logged in
        if (liff.isLoggedIn()) {
          liff.getProfile().then((p) => {
            setProfile(p);
          }).catch((err) => {
            console.error('Failed to get Profile', err);
            setError(err.toString());
          });
        } else {
          // If not logged in, proactively request Line Login
          liff.login();
        }
      })
      .catch((err) => {
        console.error('LIFF initialization failed', err);
        setError(err.toString());
      });
  }, []);

  return { profile, error, isReady, liff };
}

3. Use User Info in the Punch Card Page

Now simply call this Hook in your punch card component, and you'll instantly get the employee's name and avatar - no need for them to enter credentials!

// src/components/PunchCard.tsx
import { useLiff } from '../hooks/useLiff';

export function PunchCard() {
  const { profile, isReady, liff } = useLiff();

  if (!isReady) return <div>Loading Line system...</div>;
  if (!profile) return <div>Please login with Line first...</div>;

  const handlePunch = async () => {
    // Get a secure Access Token to send to our FastAPI backend
    const accessToken = liff.getAccessToken();
    
    await fetch('https://api.yourdomain.com/punch', {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${accessToken}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({ action: 'check-in' })
    });
    
    alert('Punch successful!');
    // After punching, directly close the Line window! Ultimate VIP experience!
    liff.closeWindow();
  };

  return (
    <div className="p-4 bg-white rounded-xl shadow-md flex flex-col items-center">
      <img src={profile.pictureUrl} alt="avatar" className="w-20 h-20 rounded-full mb-4" />
      <h2 className="text-xl font-bold mb-6">Hello, {profile.displayName}</h2>
      
      <button 
        onClick={handlePunch}
        className="w-full bg-green-500 text-white font-bold py-4 rounded-lg text-lg"
      >
        Clock In
      </button>
    </div>
  );
}

4. Why This Architecture is So Powerful?

Look closely at the liff.getAccessToken() line.
This is LIFF's most powerful feature: it generates a "key" that can only be produced by "this specific phone's Line app". We send it to our backend (FastAPI), which can verify this key with Line's servers to confirm "this person definitely isn't cheating by having someone else punch for them"!

This is the confidence booster for SaaS projects. In the next chapter, we'll implement this key verification mechanism in our FastAPI backend!

Unlock Full Tutorial

This chapter is paid content. Join the project to unlock over 5000 words of deep analysis, including 10+ god-tier Prompts and real Source Code examples!