Adding Authentication on Website
Tags: beginners, typescript, nextjs
Published: 2024-02-14 10:11:07

# Authentication

To implement authentication in Next.js, familiarize yourself with three foundational concepts:

Authentication verifies if the user is who they say they are. It requires the user to prove their identity with something they have, such as a username and password.
Session Management tracks the user's state (e.g. logged in) across multiple requests.
Authorization decides what parts of the application the user is allowed to access.
This page demonstrates how to use Next.js features to implement common authentication, authorization, and session management patterns so you can choose the best solutions based on your application's needs.

Authentication
Authentication verifies a user's identity. This happens when a user logs in, either with a username and password or through a service like Google. It's all about confirming that users are really who they claim to be, protecting both the user's data and the application from unauthorized access or fraudulent activities.

Authentication Strategies
Modern web applications commonly use several authentication strategies:

OAuth/OpenID Connect (OIDC): Enable third-party access without sharing user credentials. Ideal for social media logins and Single Sign-On (SSO) solutions. They add an identity layer with OpenID Connect.

Credentials-based login (Email + Password): A standard choice for web applications, where users log in with an email and password. Familiar and easy to implement, it requires robust security measures against threats like phishing.
Passwordless/Token-based authentication: Use email magic links or SMS one-time codes for secure, password-free access. Popular for its convenience and enhanced security, this method helps reduce password fatigue. Its limitation is the dependency on the user's email or phone availability.
Passkeys/WebAuthn: Use cryptographic credentials unique to each site, offering high security against phishing. Secure but new, this strategy can be difficult to implement.
Selecting an authentication strategy should align with your application's specific requirements, user interface considerations, and security objectives.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bxwunc8ph1pf6hvkxcbh.JPG)

Implementing Authentication
In this section, we'll explore the process of adding basic email-password authentication to a web application. While this method provides a fundamental level of security, it's worth considering more advanced options like OAuth or passwordless logins for enhanced protection against common security threats. The authentication flow we'll discuss is as follows:

The user submits their credentials through a login form.
The form calls a Server Action.
Upon successful verification, the process is completed, indicating the user's successful authentication.
If verification is unsuccessful, an error message is shown.
Consider a login form where users can input their credentials:

app/login/page.tsx

TypeScript

```
import { authenticate } from '@/app/lib/actions'
 
export default function Page() {
  return (
    <form action={authenticate}>
      <input type="email" name="email" placeholder="Email" required />
      <input type="password" name="password" placeholder="Password" required />
      <button type="submit">Login</button>
    </form>
  )
}
```
The form above has two input fields for capturing the user's email and password. On submission, it calls the authenticate Server Action.

You can then call your Authentication Provider's API in the Server Action to handle authentication:

`app/lib/actions.ts`

TypeScript

```'use server'
 
import { signIn } from '@/auth'
 
export async function authenticate(formData: FormData) {
  try {
    await signIn('credentials', formData)
  } catch (error) {
    if (error) {
      switch (error.type) {
        case 'CredentialsSignin':
          return 'Invalid credentials.'
        default:
          return 'Something went wrong.'
      }
    }
    throw error
  }
}
```
In this code, the signIn method checks the credentials against stored user data. After the authentication provider processes the credentials, there are two possible outcomes:

Successful Authentication: This outcome implies that the login was successful. Further actions, such as accessing protected routes and fetching user information, can then be initiated.
Failed Authentication: In cases where the credentials are incorrect or an error is encountered, the function returns a corresponding error message to indicate the authentication failure.
Finally, in your login-form.tsx component, you can use React's useFormState to call the Server Action and handle form errors, and use useFormStatus to handle the pending state of the form:

`app/login/page.tsx`

TypeScript
```
'use client'
 
import { authenticate } from '@/app/lib/actions'
import { useFormState, useFormStatus } from 'react-dom'
 
export default function Page() {
  const [errorMessage, dispatch] = useFormState(authenticate, undefined)
 
  return (
    <form action={dispatch}>
      <input type="email" name="email" placeholder="Email" required />
      <input type="password" name="password" placeholder="Password" required />
      <div>{errorMessage && <p>{errorMessage}</p>}</div>
      <LoginButton />
    </form>
  )
}
 
function LoginButton() {
  const { pending } = useFormStatus()
 
  return (
    <button aria-disabled={pending} type="submit">
      Login
    </button>
  )
}
```
For a more streamlined authentication setup in Next.js projects, especially when offering multiple login methods, consider using a comprehensive authentication solution.

Authorization