Login Flow
The OAuth handler can authenticate users, but the interface still needs login and logout controls plus session-aware navigation.
Next.js auth libraries expose hooks such as useSession or useUser for conditional UI. Nuxt's useUserSession returns the login state, user data, and a clear function for logout.
Outcome
Build a login page, add logout functionality, and update the nav to reflect auth state.
Fast Track
- Build the login page with a "Sign in with GitHub" link
- Add
useUserSessionto the layout and conditionally show auth links - Wire up the logout button
Hands-on exercise 3.2
Build the user-facing auth experience.
Requirements:
- Update
app/pages/login.vuewith a GitHub login link and error handling - Redirect already-logged-in users away from the login page
- Update
app/layouts/default.vueto show Favorites and Visited links when logged in - Show the user's GitHub username and a logout button when logged in
- Show a "Log in" link when logged out
Implementation hints:
useUserSession()returns{ loggedIn, user, clear }.loggedInis a boolean ref,useris the session data from your OAuth handler,clearlogs the user out- The login link should be a plain
<a href="/auth/github">, not aNuxtLink. It triggers a server redirect, not client-side navigation navigateTo("/springs")is Nuxt's programmatic navigation. Use it for redirects in<script setup>v-if/v-elseon the template handles conditional rendering
The login page needs a heading, error state, and link that starts the OAuth flow:
<script setup lang="ts">
const { loggedIn } = useUserSession();
// Redirect if already logged in
if (loggedIn.value) {
navigateTo("/springs");
}
const route = useRoute();
const hasError = computed(() => route.query.error === "auth");
</script>
<template>
<div>
<h1>Log In</h1>
<p>
Sign in with GitHub to save favorites, track visited springs, and leave
reviews.
</p>
<p v-if="hasError">
Something went wrong with authentication. Please try again.
</p>
<a href="/auth/github">
Sign in with GitHub
</a>
</div>
</template>The check at the top redirects authenticated users to /springs from <script setup>.
Use a regular <a> tag for the login link because /auth/github is a server route that redirects to GitHub. NuxtLink would attempt client-side navigation instead.
The error state uses route.query.error to check if the OAuth handler redirected back with ?error=auth. Remember our handler from the last lesson: sendRedirect(event, "/login?error=auth"). This is where that query parameter gets consumed.
Now let's update the layout to show auth state in the nav:
<script setup lang="ts">
const { loggedIn, user, clear } = useUserSession();
</script>
<template>
<div>
<header>
<nav>
<NuxtLink to="/">
Hot Springs Finder
</NuxtLink>
<div>
<NuxtLink to="/springs">
Browse
</NuxtLink>
<template v-if="loggedIn">
<NuxtLink to="/favorites">
Favorites
</NuxtLink>
<NuxtLink to="/visited">
Visited
</NuxtLink>
<div>
<span>{{ user?.login }}</span>
<button @click="clear">
Log out
</button>
</div>
</template>
<NuxtLink v-else to="/login">
Log in
</NuxtLink>
</div>
</nav>
</header>
<main>
<slot />
</main>
<footer>
Hot Springs Finder — Built with Nuxt
</footer>
</div>
</template>The <template v-if="loggedIn"> block is a Vue pattern for grouping multiple elements under one condition without adding an extra DOM node. In React, you'd use a fragment: {loggedIn && <>...</>}. Vue's <template> with a directive serves the same purpose.
The clear function removes the session and its cookie. useUserSession updates the reactive auth state after logout.
Try It
- Make sure you're logged out (clear cookies or click "Log out" if available)
- Visit
http://localhost:3000. You should see "Browse" and "Log in" in the nav - Click "Log in." You'll see the login page with a "Sign in with GitHub" button
- Click it. Authorize with GitHub. You should land on
/springs - The nav should now show: Browse, Favorites, Visited, your GitHub username, and "Log out"
- Click "Log out." The nav reverts to showing only "Browse" and "Log in"
- Visit
http://localhost:3000/loginwhile logged in. You should be redirected to/springs
Commit
git add -A && git commit -m "feat(auth): add login page and auth-aware navigation"Done-When
- The login page shows a "Sign in with GitHub" button
- Error state appears when redirected with
?error=auth - The nav shows Favorites, Visited, username, and Log out when authenticated
- The nav shows only Browse and Log in when unauthenticated
- Logging out clears the session and updates the nav immediately
Solution
<script setup lang="ts">
const { loggedIn } = useUserSession();
if (loggedIn.value) {
navigateTo("/springs");
}
const route = useRoute();
const hasError = computed(() => route.query.error === "auth");
</script>
<template>
<div>
<h1>Log In</h1>
<p>
Sign in with GitHub to save favorites, track visited springs, and leave
reviews.
</p>
<p v-if="hasError">
Something went wrong with authentication. Please try again.
</p>
<a href="/auth/github">
Sign in with GitHub
</a>
</div>
</template><script setup lang="ts">
const { loggedIn, user, clear } = useUserSession();
</script>
<template>
<div>
<header>
<nav>
<NuxtLink to="/">
Hot Springs Finder
</NuxtLink>
<div>
<NuxtLink to="/springs">
Browse
</NuxtLink>
<template v-if="loggedIn">
<NuxtLink to="/favorites">
Favorites
</NuxtLink>
<NuxtLink to="/visited">
Visited
</NuxtLink>
<div>
<span>{{ user?.login }}</span>
<button @click="clear">
Log out
</button>
</div>
</template>
<NuxtLink v-else to="/login">
Log in
</NuxtLink>
</div>
</nav>
</header>
<main>
<slot />
</main>
<footer>
Hot Springs Finder — Built with Nuxt
</footer>
</div>
</template>Was this helpful?