Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save ShaikhZayan/ffb16b87baef36519b12c9856768fca1 to your computer and use it in GitHub Desktop.

Select an option

Save ShaikhZayan/ffb16b87baef36519b12c9856768fca1 to your computer and use it in GitHub Desktop.

Revisions

  1. ShaikhZayan revised this gist Jul 25, 2024. No changes.
  2. ShaikhZayan revised this gist Jul 25, 2024. No changes.
  3. ShaikhZayan revised this gist Jul 25, 2024. 1 changed file with 43 additions and 36 deletions.
    79 changes: 43 additions & 36 deletions FASTAPI-OAuth2-System-Integration-With-Next.js.md
    Original file line number Diff line number Diff line change
    @@ -3,6 +3,7 @@ You can use FastAPI with OAuth2 for authentication and integrate it with a Next.
    ### 1. Set Up FastAPI with OAuth2
    First, you'll need to set up FastAPI with OAuth2 for authentication. Here's a basic example:


    #### FastAPI OAuth2 Setup

    1. **Install the necessary dependencies:**
    @@ -18,7 +19,7 @@ First, you'll need to set up FastAPI with OAuth2 for authentication. Here's a ba
    from jose import JWTError, jwt
    from passlib.context import CryptContext
    from datetime import datetime, timedelta
    from typing import Optional
    from typing import Optional, Dict

    app = FastAPI()

    @@ -34,7 +35,7 @@ First, you'll need to set up FastAPI with OAuth2 for authentication. Here's a ba
    oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")

    # In-memory user storage for demonstration purposes
    fake_users_db = {
    fake_users_db: Dict[str, Dict[str, str]] = {
    "user@example.com": {
    "username": "user",
    "full_name": "User Example",
    @@ -44,23 +45,22 @@ First, you'll need to set up FastAPI with OAuth2 for authentication. Here's a ba
    }
    }

    def verify_password(plain_password, hashed_password):
    def verify_password(plain_password: str, hashed_password: str) -> bool:
    return pwd_context.verify(plain_password, hashed_password)

    def get_user(db, email: str):
    def get_user(db: Dict[str, Dict[str, str]], email: str) -> Optional[Dict[str, str]]:
    if email in db:
    user_dict = db[email]
    return user_dict
    return db[email]

    def authenticate_user(fake_db, email: str, password: str):
    def authenticate_user(fake_db: Dict[str, Dict[str, str]], email: str, password: str) -> Optional[Dict[str, str]]:
    user = get_user(fake_db, email)
    if not user:
    return False
    return None
    if not verify_password(password, user['hashed_password']):
    return False
    return None
    return user

    def create_access_token(data: dict, expires_delta: Optional[timedelta] = None):
    def create_access_token(data: dict, expires_delta: Optional[timedelta] = None) -> str:
    to_encode = data.copy()
    if expires_delta:
    expire = datetime.utcnow() + expires_delta
    @@ -85,7 +85,7 @@ First, you'll need to set up FastAPI with OAuth2 for authentication. Here's a ba
    )
    return {"access_token": access_token, "token_type": "bearer"}

    async def get_current_user(token: str = Depends(oauth2_scheme)):
    async def get_current_user(token: str = Depends(oauth2_scheme)) -> Optional[Dict[str, str]]:
    credentials_exception = HTTPException(
    status_code=status.HTTP_401_UNAUTHORIZED,
    detail="Could not validate credentials",
    @@ -104,7 +104,7 @@ First, you'll need to set up FastAPI with OAuth2 for authentication. Here's a ba
    return user

    @app.get("/users/me")
    async def read_users_me(current_user: dict = Depends(get_current_user)):
    async def read_users_me(current_user: Dict[str, str] = Depends(get_current_user)):
    return current_user
    ```

    @@ -119,21 +119,25 @@ First, you'll need to set up FastAPI with OAuth2 for authentication. Here's a ba

    2. **Create an authentication provider in Next.js using `next-auth`:**

    ```javascript
    // pages/api/auth/[...nextauth].js
    ```typescript
    // pages/api/auth/[...nextauth].ts
    import NextAuth from 'next-auth';
    import Providers from 'next-auth/providers';
    import CredentialsProvider from 'next-auth/providers/credentials';
    import axios from 'axios';

    export default NextAuth({
    providers: [
    Providers.Credentials({
    CredentialsProvider({
    name: 'Credentials',
    credentials: {
    email: { label: 'Email', type: 'text' },
    password: { label: 'Password', type: 'password' },
    },
    authorize: async (credentials) => {
    try {
    const res = await axios.post('http://localhost:8000/token', {
    username: credentials.email,
    password: credentials.password,
    username: credentials?.email,
    password: credentials?.password,
    });

    if (res.status === 200) {
    @@ -149,13 +153,13 @@ First, you'll need to set up FastAPI with OAuth2 for authentication. Here's a ba
    }),
    ],
    callbacks: {
    async jwt(token, user) {
    async jwt({ token, user }) {
    if (user) {
    token.accessToken = user.token;
    }
    return token;
    },
    async session(session, token) {
    async session({ session, token }) {
    session.accessToken = token.accessToken;
    return session;
    },
    @@ -168,24 +172,24 @@ First, you'll need to set up FastAPI with OAuth2 for authentication. Here's a ba

    3. **Create a sign-in page:**

    ```javascript
    // pages/auth/signin.js
    ```typescript
    // pages/auth/signin.tsx
    import { useState } from 'react';
    import { signIn } from 'next-auth/client';
    import { signIn } from 'next-auth/react';

    export default function SignIn() {
    const [email, setEmail] = useState('');
    const [password, setPassword] = useState('');
    const [email, setEmail] = useState<string>('');
    const [password, setPassword] = useState<string>('');

    const handleSubmit = async (e) => {
    const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
    e.preventDefault();
    const result = await signIn('credentials', {
    redirect: false,
    email,
    password,
    });

    if (result.error) {
    if (result?.error) {
    // handle error
    console.error(result.error);
    } else {
    @@ -216,12 +220,12 @@ First, you'll need to set up FastAPI with OAuth2 for authentication. Here's a ba

    4. **Use the authentication token in your API calls:**

    ```javascript
    ```typescript
    import axios from 'axios';
    import { useSession } from 'next-auth/client';
    import { useSession } from 'next-auth/react';

    const fetchData = async () => {
    const [session] = useSession();
    const { data: session } = useSession();
    if (session) {
    const res = await axios.get('http://localhost:8000/users/me', {
    headers: {
    @@ -236,17 +240,19 @@ First, you'll need to set up FastAPI with OAuth2 for authentication. Here's a ba
    ```

    ### 3. Secure Next.js Routes
    You can secure your Next.js routes by checking if the user is authenticated using the `getSession` method from `next-auth/client`.

    ```javascript
    // pages/protected.js
    import { getSession } from 'next-auth/client';
    You can secure your Next.js routes by checking if the user is authenticated using the `getSession` method from `next-auth/react`.

    ```typescript
    // pages/protected.tsx
    import { GetServerSideProps } from 'next';
    import { getSession } from 'next-auth/react';

    export default function ProtectedPage() {
    return <div>Protected content</div>;
    }

    export async function getServerSideProps(context) {
    export const getServerSideProps: GetServerSideProps = async (context) => {
    const session = await getSession(context);

    if (!session) {
    @@ -261,10 +267,11 @@ export async function getServerSideProps(context) {
    return {
    props: { session },
    };
    }
    };
    ```

    ### Summary

    - **FastAPI** handles authentication, issuing JWT tokens for authenticated users.
    - **Next.js** uses `next-auth` to manage authentication on the client side, obtaining tokens from FastAPI.
    - API calls from the frontend include the JWT token in the authorization header to access protected endpoints in FastAPI.
  4. ShaikhZayan renamed this gist Jul 25, 2024. 1 changed file with 0 additions and 0 deletions.
  5. ShaikhZayan revised this gist Jul 25, 2024. No changes.
  6. ShaikhZayan renamed this gist Jul 25, 2024. 1 changed file with 0 additions and 0 deletions.
  7. ShaikhZayan revised this gist Jul 25, 2024. No changes.
  8. ShaikhZayan revised this gist Jul 25, 2024. 1 changed file with 3 additions and 1 deletion.
    4 changes: 3 additions & 1 deletion FASTAPI-O2Auth-System-Integrated-With-Next.js.md
    Original file line number Diff line number Diff line change
    @@ -269,4 +269,6 @@ export async function getServerSideProps(context) {
    - **Next.js** uses `next-auth` to manage authentication on the client side, obtaining tokens from FastAPI.
    - API calls from the frontend include the JWT token in the authorization header to access protected endpoints in FastAPI.

    By following this setup, you can have a secure and functional login system with FastAPI as the backend and Next.js as the frontend.
    By following this setup, you can have a secure and functional login system with FastAPI as the backend and Next.js as the frontend.

    Make Sure To Star The Repo If You Think It's Useful TY!
  9. ShaikhZayan renamed this gist Jul 25, 2024. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion test.md → ...-O2Auth-System-Integrated-With-Next.js.md
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,4 @@
    Yes, you can use FastAPI with OAuth2 for authentication and integrate it with a Next.js frontend to create a login system. You can manage your backend logic and authentication in FastAPI and handle the frontend logic, including authorization, in Next.js. Here's a high-level overview of how you can achieve this:
    You can use FastAPI with OAuth2 for authentication and integrate it with a Next.js frontend to create a login system. You can manage your backend logic and authentication in FastAPI and handle the frontend logic, including authorization, in Next.js. Here's a high-level overview of how you can achieve this:

    ### 1. Set Up FastAPI with OAuth2
    First, you'll need to set up FastAPI with OAuth2 for authentication. Here's a basic example:
  10. ShaikhZayan revised this gist Jul 25, 2024. 1 changed file with 259 additions and 338 deletions.
    597 changes: 259 additions & 338 deletions test.md
    Original file line number Diff line number Diff line change
    @@ -1,351 +1,272 @@
    Here's a formatted guide for adding a cookie-based authentication system to a Next.js application while integrating with FastAPI. You can include this in your GitHub README:

    ---

    ## Cookie-Based Authentication System with Next.js and FastAPI

    Adding a cookie-based authentication system to Next.js while integrating with FastAPI involves setting up both the backend and frontend to handle user signup, login, and authentication using cookies.

    ### 1. FastAPI Setup

    #### FastAPI OAuth2 Setup with Signup

    First, add signup functionality to your FastAPI app and configure OAuth2 to handle cookies.

    **Install dependencies:**

    ```bash
    pip install fastapi uvicorn python-jose passlib
    ```

    **FastAPI app with signup and OAuth2:**

    ```python
    from fastapi import FastAPI, Depends, HTTPException, status
    from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
    from jose import JWTError, jwt
    from passlib.context import CryptContext
    from datetime import datetime, timedelta
    from typing import Optional
    from pydantic import BaseModel

    app = FastAPI()

    SECRET_KEY = "your_secret_key"
    ALGORITHM = "HS256"
    ACCESS_TOKEN_EXPIRE_MINUTES = 30

    pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
    oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")

    # In-memory user storage for demonstration purposes
    fake_users_db = {}

    class User(BaseModel):
    username: str
    email: str
    full_name: Optional[str] = None
    disabled: Optional[bool] = None

    class UserInDB(User):
    hashed_password: str

    def verify_password(plain_password, hashed_password):
    return pwd_context.verify(plain_password, hashed_password)

    def get_user(db, email: str):
    if email in db:
    user_dict = db[email]
    return UserInDB(**user_dict)

    def authenticate_user(fake_db, email: str, password: str):
    user = get_user(fake_db, email)
    if not user:
    return False
    if not verify_password(password, user.hashed_password):
    return False
    return user

    def create_access_token(data: dict, expires_delta: Optional[timedelta] = None):
    to_encode = data.copy()
    if expires_delta:
    expire = datetime.utcnow() + expires_delta
    else:
    expire = datetime.utcnow() + timedelta(minutes=15)
    to_encode.update({"exp": expire})
    encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
    return encoded_jwt

    @app.post("/token")
    async def login_for_access_token(form_data: OAuth2PasswordRequestForm = Depends()):
    user = authenticate_user(fake_users_db, form_data.username, form_data.password)
    if not user:
    raise HTTPException(
    status_code=status.HTTP_401_UNAUTHORIZED,
    detail="Incorrect username or password",
    headers={"WWW-Authenticate": "Bearer"},
    )
    access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
    access_token = create_access_token(
    data={"sub": user.email}, expires_delta=access_token_expires
    )
    return {"access_token": access_token, "token_type": "bearer"}

    @app.post("/signup")
    async def signup(email: str, password: str, full_name: Optional[str] = None):
    if email in fake_users_db:
    raise HTTPException(status_code=400, detail="Email already registered")
    hashed_password = pwd_context.hash(password)
    fake_users_db[email] = {
    "username": email,
    "email": email,
    "full_name": full_name,
    "hashed_password": hashed_password,
    "disabled": False,
    }
    return {"message": "User created"}

    async def get_current_user(token: str = Depends(oauth2_scheme)):
    credentials_exception = HTTPException(
    status_code=status.HTTP_401_UNAUTHORIZED,
    detail="Could not validate credentials",
    headers={"WWW-Authenticate": "Bearer"},
    )
    try:
    payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
    email: str = payload.get("sub")
    if email is None:
    raise credentials_exception
    except JWTError:
    raise credentials_exception
    user = get_user(fake_users_db, email=email)
    if user is None:
    raise credentials_exception
    return user

    @app.get("/users/me")
    async def read_users_me(current_user: User = Depends(get_current_user)):
    return current_user
    ```

    ### 2. Next.js Setup

    #### Dependencies

    **Install the necessary packages:**

    ```bash
    npm install next-auth axios cookie
    ```

    **Create a `next-auth` configuration file:**

    ```javascript
    // pages/api/auth/[...nextauth].js
    import NextAuth from 'next-auth';
    import CredentialsProvider from 'next-auth/providers/credentials';
    import axios from 'axios';

    export default NextAuth({
    providers: [
    CredentialsProvider({
    name: 'Credentials',
    credentials: {
    email: { label: 'Email', type: 'text' },
    password: { label: 'Password', type: 'password' },
    },
    authorize: async (credentials) => {
    try {
    const res = await axios.post('http://localhost:8000/token', {
    username: credentials.email,
    password: credentials.password,
    });

    if (res.status === 200) {
    return { accessToken: res.data.access_token };
    } else {
    return null;
    }
    } catch (error) {
    console.error(error);
    return null;
    }
    },
    }),
    ],
    callbacks: {
    async jwt({ token, user }) {
    if (user) {
    token.accessToken = user.accessToken;
    }
    return token;
    },
    async session({ session, token }) {
    session.accessToken = token.accessToken;
    return session;
    },
    },
    pages: {
    signIn: '/auth/signin',
    signUp: '/auth/signup',
    },
    });
    ```

    **Create a signup page:**

    ```javascript
    // pages/auth/signup.js
    import { useState } from 'react';
    import axios from 'axios';

    export default function Signup() {
    const [email, setEmail] = useState('');
    const [password, setPassword] = useState('');
    const [fullName, setFullName] = useState('');

    const handleSubmit = async (e) => {
    e.preventDefault();
    try {
    await axios.post('http://localhost:8000/signup', { email, password, full_name: fullName });
    alert('Signup successful');
    } catch (error) {
    console.error(error);
    alert('Signup failed');
    }
    };

    return (
    <form onSubmit={handleSubmit}>
    <input
    type="text"
    placeholder="Full Name"
    value={fullName}
    onChange={(e) => setFullName(e.target.value)}
    />
    <input
    type="email"
    placeholder="Email"
    value={email}
    onChange={(e) => setEmail(e.target.value)}
    />
    <input
    type="password"
    placeholder="Password"
    value={password}
    onChange={(e) => setPassword(e.target.value)}
    />
    <button type="submit">Sign Up</button>
    </form>
    );
    }
    ```

    **Create a sign-in page:**

    ```javascript
    // pages/auth/signin.js
    import { useState } from 'react';
    import { signIn } from 'next-auth/react';

    export default function SignIn() {
    const [email, setEmail] = useState('');
    const [password, setPassword] = useState('');

    const handleSubmit = async (e) => {
    e.preventDefault();
    const result = await signIn('credentials', {
    redirect: false,
    email,
    password,
    });

    if (result.error) {
    alert(result.error);
    } else {
    window.location.href = '/';
    }
    };

    return (
    <form onSubmit={handleSubmit}>
    <input
    type="email"
    placeholder="Email"
    value={email}
    onChange={(e) => setEmail(e.target.value)}
    />
    <input
    type="password"
    placeholder="Password"
    value={password}
    onChange={(e) => setPassword(e.target.value)}
    />
    <button type="submit">Sign In</button>
    </form>
    );
    }
    ```

    **Handle authentication with cookies in API calls:**

    ```javascript
    // utils/axios.js
    import axios from 'axios';
    import { getSession } from 'next-auth/react';

    export const fetchWithAuth = async (url, options = {}) => {
    const session = await getSession();
    const headers = session ? { Authorization: `Bearer ${session.accessToken}` } : {};

    return axios(url, {
    ...options,
    headers: { ...headers, ...options.headers },
    });
    };
    ```

    **Use the `fetchWithAuth` utility to make authenticated API calls:**
    Yes, you can use FastAPI with OAuth2 for authentication and integrate it with a Next.js frontend to create a login system. You can manage your backend logic and authentication in FastAPI and handle the frontend logic, including authorization, in Next.js. Here's a high-level overview of how you can achieve this:

    ### 1. Set Up FastAPI with OAuth2
    First, you'll need to set up FastAPI with OAuth2 for authentication. Here's a basic example:

    #### FastAPI OAuth2 Setup

    1. **Install the necessary dependencies:**
    ```bash
    pip install fastapi uvicorn python-jose passlib
    ```

    2. **Create the FastAPI app:**

    ```python
    from fastapi import FastAPI, Depends, HTTPException, status
    from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
    from jose import JWTError, jwt
    from passlib.context import CryptContext
    from datetime import datetime, timedelta
    from typing import Optional

    app = FastAPI()

    # Secret key to encode and decode JWT tokens
    SECRET_KEY = "your_secret_key"
    ALGORITHM = "HS256"
    ACCESS_TOKEN_EXPIRE_MINUTES = 30

    # Password hashing context
    pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")

    # OAuth2 scheme
    oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")

    # In-memory user storage for demonstration purposes
    fake_users_db = {
    "user@example.com": {
    "username": "user",
    "full_name": "User Example",
    "email": "user@example.com",
    "hashed_password": pwd_context.hash("password"),
    "disabled": False,
    }
    }

    def verify_password(plain_password, hashed_password):
    return pwd_context.verify(plain_password, hashed_password)

    def get_user(db, email: str):
    if email in db:
    user_dict = db[email]
    return user_dict

    def authenticate_user(fake_db, email: str, password: str):
    user = get_user(fake_db, email)
    if not user:
    return False
    if not verify_password(password, user['hashed_password']):
    return False
    return user

    def create_access_token(data: dict, expires_delta: Optional[timedelta] = None):
    to_encode = data.copy()
    if expires_delta:
    expire = datetime.utcnow() + expires_delta
    else:
    expire = datetime.utcnow() + timedelta(minutes=15)
    to_encode.update({"exp": expire})
    encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
    return encoded_jwt

    @app.post("/token")
    async def login_for_access_token(form_data: OAuth2PasswordRequestForm = Depends()):
    user = authenticate_user(fake_users_db, form_data.username, form_data.password)
    if not user:
    raise HTTPException(
    status_code=status.HTTP_401_UNAUTHORIZED,
    detail="Incorrect username or password",
    headers={"WWW-Authenticate": "Bearer"},
    )
    access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
    access_token = create_access_token(
    data={"sub": user['email']}, expires_delta=access_token_expires
    )
    return {"access_token": access_token, "token_type": "bearer"}

    async def get_current_user(token: str = Depends(oauth2_scheme)):
    credentials_exception = HTTPException(
    status_code=status.HTTP_401_UNAUTHORIZED,
    detail="Could not validate credentials",
    headers={"WWW-Authenticate": "Bearer"},
    )
    try:
    payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
    email: str = payload.get("sub")
    if email is None:
    raise credentials_exception
    except JWTError:
    raise credentials_exception
    user = get_user(fake_users_db, email=email)
    if user is None:
    raise credentials_exception
    return user

    @app.get("/users/me")
    async def read_users_me(current_user: dict = Depends(get_current_user)):
    return current_user
    ```

    ### 2. Integrate with Next.js

    #### Next.js Authentication

    1. **Install the necessary dependencies:**
    ```bash
    npm install next-auth axios
    ```

    2. **Create an authentication provider in Next.js using `next-auth`:**

    ```javascript
    // pages/api/auth/[...nextauth].js
    import NextAuth from 'next-auth';
    import Providers from 'next-auth/providers';
    import axios from 'axios';

    export default NextAuth({
    providers: [
    Providers.Credentials({
    name: 'Credentials',
    authorize: async (credentials) => {
    try {
    const res = await axios.post('http://localhost:8000/token', {
    username: credentials.email,
    password: credentials.password,
    });

    if (res.status === 200) {
    return { token: res.data.access_token };
    } else {
    return null;
    }
    } catch (error) {
    console.error(error);
    return null;
    }
    },
    }),
    ],
    callbacks: {
    async jwt(token, user) {
    if (user) {
    token.accessToken = user.token;
    }
    return token;
    },
    async session(session, token) {
    session.accessToken = token.accessToken;
    return session;
    },
    },
    pages: {
    signIn: '/auth/signin',
    },
    });
    ```

    3. **Create a sign-in page:**

    ```javascript
    // pages/auth/signin.js
    import { useState } from 'react';
    import { signIn } from 'next-auth/client';

    export default function SignIn() {
    const [email, setEmail] = useState('');
    const [password, setPassword] = useState('');

    const handleSubmit = async (e) => {
    e.preventDefault();
    const result = await signIn('credentials', {
    redirect: false,
    email,
    password,
    });

    if (result.error) {
    // handle error
    console.error(result.error);
    } else {
    // redirect to home page
    window.location.href = '/';
    }
    };

    return (
    <form onSubmit={handleSubmit}>
    <input
    type="email"
    placeholder="Email"
    value={email}
    onChange={(e) => setEmail(e.target.value)}
    />
    <input
    type="password"
    placeholder="Password"
    value={password}
    onChange={(e) => setPassword(e.target.value)}
    />
    <button type="submit">Sign In</button>
    </form>
    );
    }
    ```

    4. **Use the authentication token in your API calls:**

    ```javascript
    import axios from 'axios';
    import { useSession } from 'next-auth/client';

    const fetchData = async () => {
    const [session] = useSession();
    if (session) {
    const res = await axios.get('http://localhost:8000/users/me', {
    headers: {
    Authorization: `Bearer ${session.accessToken}`,
    },
    });
    console.log(res.data);
    }
    };

    fetchData();
    ```

    ### 3. Secure Next.js Routes
    You can secure your Next.js routes by checking if the user is authenticated using the `getSession` method from `next-auth/client`.

    ```javascript
    // pages/protected.js
    import { useEffect, useState } from 'react';
    import { fetchWithAuth } from '../utils/axios';
    import { getSession } from 'next-auth/client';

    export default function ProtectedPage() {
    const [data, setData] = useState(null);

    useEffect(() => {
    const fetchData = async () => {
    try {
    const response = await fetchWithAuth('http://localhost:8000/users/me');
    setData(response.data);
    } catch (error) {
    console.error(error);
    }
    };
    return <div>Protected content</div>;
    }

    fetchData();
    }, []);
    export async function getServerSideProps(context) {
    const session = await getSession(context);

    return (
    <div>
    <h1>Protected Content</h1>
    {data ? <pre>{JSON.stringify(data, null, 2)}</
    if (!session) {
    return {
    redirect: {
    destination: '/auth/signin',
    permanent: false,
    },
    };
    }

    pre> : <p>Loading...</p>}
    </div>
    );
    return {
    props: { session },
    };
    }
    ```

    ### Summary
    - **FastAPI**: Manages signup and login, issuing JWT tokens.
    - **Next.js**: Utilizes `next-auth` for authentication and cookies, with dedicated signup and login pages.
    - **Cookies**: Stored and sent with each request, enabling authenticated API calls to FastAPI endpoints.

    Feel free to customize further according to your needs!

    ---
    - **FastAPI** handles authentication, issuing JWT tokens for authenticated users.
    - **Next.js** uses `next-auth` to manage authentication on the client side, obtaining tokens from FastAPI.
    - API calls from the frontend include the JWT token in the authorization header to access protected endpoints in FastAPI.

    You can copy this directly into your README file, and it should provide clear instructions for setting up cookie-based authentication between Next.js and FastAPI.
    By following this setup, you can have a secure and functional login system with FastAPI as the backend and Next.js as the frontend.
  11. ShaikhZayan revised this gist Jul 25, 2024. 2 changed files with 351 additions and 1 deletion.
    1 change: 0 additions & 1 deletion test
    Original file line number Diff line number Diff line change
    @@ -1 +0,0 @@
    #Hello
    351 changes: 351 additions & 0 deletions test.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,351 @@
    Here's a formatted guide for adding a cookie-based authentication system to a Next.js application while integrating with FastAPI. You can include this in your GitHub README:

    ---

    ## Cookie-Based Authentication System with Next.js and FastAPI

    Adding a cookie-based authentication system to Next.js while integrating with FastAPI involves setting up both the backend and frontend to handle user signup, login, and authentication using cookies.

    ### 1. FastAPI Setup

    #### FastAPI OAuth2 Setup with Signup

    First, add signup functionality to your FastAPI app and configure OAuth2 to handle cookies.

    **Install dependencies:**

    ```bash
    pip install fastapi uvicorn python-jose passlib
    ```

    **FastAPI app with signup and OAuth2:**

    ```python
    from fastapi import FastAPI, Depends, HTTPException, status
    from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
    from jose import JWTError, jwt
    from passlib.context import CryptContext
    from datetime import datetime, timedelta
    from typing import Optional
    from pydantic import BaseModel

    app = FastAPI()

    SECRET_KEY = "your_secret_key"
    ALGORITHM = "HS256"
    ACCESS_TOKEN_EXPIRE_MINUTES = 30

    pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
    oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")

    # In-memory user storage for demonstration purposes
    fake_users_db = {}

    class User(BaseModel):
    username: str
    email: str
    full_name: Optional[str] = None
    disabled: Optional[bool] = None

    class UserInDB(User):
    hashed_password: str

    def verify_password(plain_password, hashed_password):
    return pwd_context.verify(plain_password, hashed_password)

    def get_user(db, email: str):
    if email in db:
    user_dict = db[email]
    return UserInDB(**user_dict)

    def authenticate_user(fake_db, email: str, password: str):
    user = get_user(fake_db, email)
    if not user:
    return False
    if not verify_password(password, user.hashed_password):
    return False
    return user

    def create_access_token(data: dict, expires_delta: Optional[timedelta] = None):
    to_encode = data.copy()
    if expires_delta:
    expire = datetime.utcnow() + expires_delta
    else:
    expire = datetime.utcnow() + timedelta(minutes=15)
    to_encode.update({"exp": expire})
    encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
    return encoded_jwt

    @app.post("/token")
    async def login_for_access_token(form_data: OAuth2PasswordRequestForm = Depends()):
    user = authenticate_user(fake_users_db, form_data.username, form_data.password)
    if not user:
    raise HTTPException(
    status_code=status.HTTP_401_UNAUTHORIZED,
    detail="Incorrect username or password",
    headers={"WWW-Authenticate": "Bearer"},
    )
    access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
    access_token = create_access_token(
    data={"sub": user.email}, expires_delta=access_token_expires
    )
    return {"access_token": access_token, "token_type": "bearer"}

    @app.post("/signup")
    async def signup(email: str, password: str, full_name: Optional[str] = None):
    if email in fake_users_db:
    raise HTTPException(status_code=400, detail="Email already registered")
    hashed_password = pwd_context.hash(password)
    fake_users_db[email] = {
    "username": email,
    "email": email,
    "full_name": full_name,
    "hashed_password": hashed_password,
    "disabled": False,
    }
    return {"message": "User created"}

    async def get_current_user(token: str = Depends(oauth2_scheme)):
    credentials_exception = HTTPException(
    status_code=status.HTTP_401_UNAUTHORIZED,
    detail="Could not validate credentials",
    headers={"WWW-Authenticate": "Bearer"},
    )
    try:
    payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
    email: str = payload.get("sub")
    if email is None:
    raise credentials_exception
    except JWTError:
    raise credentials_exception
    user = get_user(fake_users_db, email=email)
    if user is None:
    raise credentials_exception
    return user

    @app.get("/users/me")
    async def read_users_me(current_user: User = Depends(get_current_user)):
    return current_user
    ```

    ### 2. Next.js Setup

    #### Dependencies

    **Install the necessary packages:**

    ```bash
    npm install next-auth axios cookie
    ```

    **Create a `next-auth` configuration file:**

    ```javascript
    // pages/api/auth/[...nextauth].js
    import NextAuth from 'next-auth';
    import CredentialsProvider from 'next-auth/providers/credentials';
    import axios from 'axios';

    export default NextAuth({
    providers: [
    CredentialsProvider({
    name: 'Credentials',
    credentials: {
    email: { label: 'Email', type: 'text' },
    password: { label: 'Password', type: 'password' },
    },
    authorize: async (credentials) => {
    try {
    const res = await axios.post('http://localhost:8000/token', {
    username: credentials.email,
    password: credentials.password,
    });

    if (res.status === 200) {
    return { accessToken: res.data.access_token };
    } else {
    return null;
    }
    } catch (error) {
    console.error(error);
    return null;
    }
    },
    }),
    ],
    callbacks: {
    async jwt({ token, user }) {
    if (user) {
    token.accessToken = user.accessToken;
    }
    return token;
    },
    async session({ session, token }) {
    session.accessToken = token.accessToken;
    return session;
    },
    },
    pages: {
    signIn: '/auth/signin',
    signUp: '/auth/signup',
    },
    });
    ```

    **Create a signup page:**

    ```javascript
    // pages/auth/signup.js
    import { useState } from 'react';
    import axios from 'axios';

    export default function Signup() {
    const [email, setEmail] = useState('');
    const [password, setPassword] = useState('');
    const [fullName, setFullName] = useState('');

    const handleSubmit = async (e) => {
    e.preventDefault();
    try {
    await axios.post('http://localhost:8000/signup', { email, password, full_name: fullName });
    alert('Signup successful');
    } catch (error) {
    console.error(error);
    alert('Signup failed');
    }
    };

    return (
    <form onSubmit={handleSubmit}>
    <input
    type="text"
    placeholder="Full Name"
    value={fullName}
    onChange={(e) => setFullName(e.target.value)}
    />
    <input
    type="email"
    placeholder="Email"
    value={email}
    onChange={(e) => setEmail(e.target.value)}
    />
    <input
    type="password"
    placeholder="Password"
    value={password}
    onChange={(e) => setPassword(e.target.value)}
    />
    <button type="submit">Sign Up</button>
    </form>
    );
    }
    ```

    **Create a sign-in page:**

    ```javascript
    // pages/auth/signin.js
    import { useState } from 'react';
    import { signIn } from 'next-auth/react';

    export default function SignIn() {
    const [email, setEmail] = useState('');
    const [password, setPassword] = useState('');

    const handleSubmit = async (e) => {
    e.preventDefault();
    const result = await signIn('credentials', {
    redirect: false,
    email,
    password,
    });

    if (result.error) {
    alert(result.error);
    } else {
    window.location.href = '/';
    }
    };

    return (
    <form onSubmit={handleSubmit}>
    <input
    type="email"
    placeholder="Email"
    value={email}
    onChange={(e) => setEmail(e.target.value)}
    />
    <input
    type="password"
    placeholder="Password"
    value={password}
    onChange={(e) => setPassword(e.target.value)}
    />
    <button type="submit">Sign In</button>
    </form>
    );
    }
    ```

    **Handle authentication with cookies in API calls:**

    ```javascript
    // utils/axios.js
    import axios from 'axios';
    import { getSession } from 'next-auth/react';

    export const fetchWithAuth = async (url, options = {}) => {
    const session = await getSession();
    const headers = session ? { Authorization: `Bearer ${session.accessToken}` } : {};

    return axios(url, {
    ...options,
    headers: { ...headers, ...options.headers },
    });
    };
    ```

    **Use the `fetchWithAuth` utility to make authenticated API calls:**

    ```javascript
    // pages/protected.js
    import { useEffect, useState } from 'react';
    import { fetchWithAuth } from '../utils/axios';

    export default function ProtectedPage() {
    const [data, setData] = useState(null);

    useEffect(() => {
    const fetchData = async () => {
    try {
    const response = await fetchWithAuth('http://localhost:8000/users/me');
    setData(response.data);
    } catch (error) {
    console.error(error);
    }
    };

    fetchData();
    }, []);

    return (
    <div>
    <h1>Protected Content</h1>
    {data ? <pre>{JSON.stringify(data, null, 2)}</

    pre> : <p>Loading...</p>}
    </div>
    );
    }
    ```

    ### Summary
    - **FastAPI**: Manages signup and login, issuing JWT tokens.
    - **Next.js**: Utilizes `next-auth` for authentication and cookies, with dedicated signup and login pages.
    - **Cookies**: Stored and sent with each request, enabling authenticated API calls to FastAPI endpoints.

    Feel free to customize further according to your needs!

    ---

    You can copy this directly into your README file, and it should provide clear instructions for setting up cookie-based authentication between Next.js and FastAPI.
  12. ShaikhZayan revised this gist Jul 25, 2024. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion test
    Original file line number Diff line number Diff line change
    @@ -1 +1 @@
    # Hello
    #Hello
  13. ShaikhZayan created this gist Jul 25, 2024.
    1 change: 1 addition & 0 deletions test
    Original file line number Diff line number Diff line change
    @@ -0,0 +1 @@
    # Hello