Skip to content

Chapter 4: Authentication & Token Management

← Previous: State Management

Have you ever used a key card to access a building? You need to swipe it at the entrance, and it grants you access if it's valid. In our Local Gist Manager, GitHub authentication works similarly - you need a valid "key card" (token) to access your gists. Let's explore how this system works!

The Problem: Securely Connecting to GitHub

Imagine wanting to access your personal files in a secure building. You wouldn't want just anyone to walk in and view your documents - you need a system to verify that you're authorized to access them.

Similarly, when our application wants to access your GitHub gists: 1. We need to prove to GitHub that you've authorized our app 2. We need to do this securely without exposing your credentials 3. We want to remember your authorization so you don't have to log in every time

Personal Access Tokens: Your Digital Key Card

GitHub uses Personal Access Tokens (PATs) for authentication. These are long strings that look something like:

ghp_aBcDeFgHiJkLmNoPqRsTuVwXyZ1234567890

Think of this token as your special key card to GitHub. When you provide this token to our app, it can: - Fetch your gists - Create new gists - Update existing gists - Delete gists

But it can only do these things because GitHub recognizes the token as belonging to you.

The Token Flow: How Authentication Works

Here's how the authentication process works in our application:

sequenceDiagram participant User participant App participant Cookies participant GitHub as GitHub API User->>App: Enter GitHub token App->>GitHub: Test token validity GitHub->>App: Token valid/invalid App->>Cookies: Store valid token App->>User: Show gists Note over User,App: Later visits User->>App: Open application App->>Cookies: Check for saved token Cookies->>App: Return saved token App->>GitHub: Use token for requests GitHub->>App: Return gists App->>User: Show gists

Let's walk through this diagram: 1. You enter your GitHub token in our application 2. Our app tests if the token is valid by trying to fetch your gists 3. If valid, we store the token in your browser cookies 4. On future visits, we check for this saved token first 5. If found, we automatically use it to fetch your gists

This is like the building remembering your key card, so you don't have to swipe it every time you visit!

The TokenForm Component: Your Entry Point

The first step in our authentication process is the TokenForm component that collects your GitHub token:

const TokenForm = ({ onTokenSubmit }) => {
  const [token, setToken] = useState("");
  const [hasSavedToken, setHasSavedToken] = useState(false);

  // Check for saved token when component loads
  useEffect(() => {
    const savedToken = getTokenFromCookie();
    if (savedToken) {
      setToken(savedToken);
      setHasSavedToken(true);
    }
  }, []);

  // More code for form submission...

This component: - Creates a state variable to hold the token - Checks if there's already a saved token in your cookies - If found, it fills the input field with that token - Lets you submit the form to authenticate

To remember your token between visits, we use browser cookies. These are small pieces of data stored in your browser:

// Save token to cookies
export const saveTokenToCookie = (token) => {
  setCookie(null, 'github_token', token, {
    maxAge: 30 * 24 * 60 * 60, // 30 days
    path: '/',
    sameSite: 'strict'
  });
};

// Get token from cookies
export const getTokenFromCookie = () => {
  const cookies = parseCookies();
  return cookies['github_token'] || '';
};

The first function saves your token in a cookie that will last for 30 days. The second function retrieves your saved token when you return to the application.

Token Validation: Testing Your Key Card

When you submit your token, our application needs to check if it's valid:

const handleTokenSubmit = async (submittedToken) => {
  setToken(submittedToken);
  setLoading(true);

  try {
    // Try to fetch gists using the token
    const fetchedGists = await getGists(submittedToken);
    setGists(fetchedGists);
    // Save token to cookies when successful
    saveTokenToCookie(submittedToken);
  } catch (err) {
    setError("Failed to fetch gists. Please check your token.");
    // Clear invalid token
    removeTokenFromCookie();
  } finally {
    setLoading(false);
  }
};

This function: 1. Updates the token state with what you submitted 2. Shows a loading indicator 3. Tries to fetch your gists using that token 4. If successful, it saves the token to cookies 5. If there's an error, it shows an error message and clears any saved token

It's like trying your key card at the building entrance - if it works, great! If not, we need to get a new key card.

Using the Token for API Requests

Once we have a valid token, we use it for all requests to GitHub's API:

const getGists = async (token) => {
  const response = await fetch('https://api.github.com/gists', {
    headers: {
      'Authorization': `token ${token}`,
      'Content-Type': 'application/json'
    }
  });

  if (!response.ok) {
    throw new Error(`Failed to fetch gists`);
  }

  return response.json();
};

This function: 1. Makes a request to GitHub's API 2. Includes your token in the Authorization header 3. Throws an error if the request fails 4. Returns the gist data if successful

The token in the Authorization header is like showing your key card to access different rooms within the building. Without it, GitHub would reject your request.

Automatic Login: Using Saved Tokens

When you return to our application, we automatically check for a saved token:

useEffect(() => {
  const loadSavedToken = async () => {
    // Check for token in cookie
    const savedToken = getTokenFromCookie();

    if (savedToken) {
      setToken(savedToken);
      try {
        const fetchedGists = await getGists(savedToken);
        setGists(fetchedGists);
      } catch (err) {
        // Token is invalid, clear it
        removeTokenFromCookie();
        setToken("");
      }
    }
  };

  loadSavedToken();
}, []);

This code: 1. Runs when the application first loads 2. Checks if there's a saved token in cookies 3. If found, it tries to use that token to fetch gists 4. If the token is no longer valid, it removes it from cookies

This is like the building entrance automatically recognizing your key card from a distance when you approach, without you having to take it out of your pocket!

Logging Out: Clearing Your Token

Sometimes you want to remove your authorization. Our application provides a logout function:

const handleLogout = () => {
  setToken("");
  setGists([]);
  // Remove token from cookies
  removeTokenFromCookie();
};

This function: 1. Clears the token from the application state 2. Clears the list of gists 3. Removes the token from cookies

This is like turning in your key card when you don't need access to the building anymore.

Token Security Best Practices

Security is important when working with authentication tokens. Here are some best practices our application follows:

  1. Secure Storage: We store tokens in cookies with security flags
  2. Limited Lifespan: Tokens expire after 30 days
  3. Secure Transmission: Tokens are only sent over secure HTTPS connections
  4. Minimal Permissions: We recommend tokens with only the permissions needed

Authentication Flow in Action

Let's see how all of this works together in a real user flow:

  1. First Visit
  2. You visit Local Gist Manager for the first time
  3. The app shows the TokenForm component
  4. You enter your GitHub token and submit

  5. Token Validation

  6. The app tries to fetch your gists using the token
  7. If successful, it saves the token to cookies
  8. The app displays your gists

  9. Subsequent Visits

  10. You return to Local Gist Manager
  11. The app finds your saved token in cookies
  12. It automatically fetches your gists
  13. You see your gists without having to re-enter your token

  14. Logout

  15. You click "Clear Token" in the header
  16. The app removes the token from cookies
  17. You return to the token entry screen

Creating a GitHub Personal Access Token

If you don't have a token yet, here's how to create one:

  1. Go to GitHub Settings > Personal Access Tokens
  2. Click "Generate new token"
  3. Give your token a descriptive name (e.g., "Local Gist Manager")
  4. Select the "gist" scope to give access to your gists
  5. Click "Generate token"
  6. Copy the generated token (you won't be able to see it again!)

Remember that this token gives access to your gists, so keep it secure and don't share it.

Conclusion

In this chapter, we've learned about Authentication & Token Management in our Local Gist Manager application. We've seen how Personal Access Tokens work as digital key cards for GitHub, how we validate and store these tokens in cookies, and how we use them to access your gists.

This authentication system ensures that only you can access your gists through our application, while also making the experience convenient by remembering your authentication between visits.

In the next chapter, we'll explore GitHub API Integration, which builds on this authentication system to communicate with GitHub's servers.