# Login Process

## How the login process works

<figure><img src="/files/Cv9fvO4JZ476C78UUrAQ" alt=""><figcaption></figcaption></figure>

1. User logs in with username and password
2. API checks for user in the database
3. API checks for the users password if user is found
4. API hashes password provided again
5. The hashed password provided should match the hashed password in the database
6. If they match, user receives token

## How to code this

* Fist we will have to set up a <mark style="color:green;">`auth.py`</mark> file to keep it separate in the <mark style="color:green;">`routers`</mark> folder
  * This makes more sense then having it in a single file

```python
from fastapi import APIRouter, Depends, status, HTTPException, Response
from sqlalchemy.orm import Session

from .. import database 

router = APIRouter(
    tags=['Authentification']
)

@router.post("/login")
def login(db: Session = Depends(database.get_db())):
    pass 

```

* We also need to create a schema for the user login

```python
class UserLogin(BaseModel):
    email: EmailStr
    password: str
```

* Now we will store this in our function

```python
@router.post("/login")
def login(user_credentials: schemas.UserLogin, db: Session = Depends(database.get_db())):
    pass 
```

* We have to make a request to our database, specifically our users table to retrieve the user based on email

```python
from .. import database, schemas, models

@router.post("/login")
def login(user_credentials: schemas.UserLogin, db: Session = Depends(database.get_db())):
    

    user = db.query(models.User).filter(models.User.email == user_credentials.email).first
```

* If we do not have a user, we need to raise an exception

```python
@router.post("/login")
def login(user_credentials: schemas.UserLogin, db: Session = Depends(database.get_db())):
    

    user = db.query(models.User).filter(models.User.email == user_credentials.email).first

    if not user:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"Invalid Credentials")
```

* Now that we have the password, we need to compare this to the hashed password in our database
* First we need to hash the provided password (we will create this in the <mark style="color:green;">`utils.py`</mark> file)

```python
def verify(plain_password, hashed_password):
    return pwd_context.verify(plain_password, hashed_password)
```

{% hint style="info" %}
The beauty about <mark style="color:yellow;">`CryptContext`</mark> is that it has the <mark style="color:orange;">`.verify`</mark> method which allows us to hash the password and compare it directly without additional logic
{% endhint %}

* Now we can import this function in our <mark style="color:green;">`auth.py`</mark> file and verify the password
* Additionally raise an exception if the password does not match

```python
from .. import database, schemas, models, utils

@router.post("/login")
def login(user_credentials: schemas.UserLogin, db: Session = Depends(database.get_db())):
    

    user = db.query(models.User).filter(models.User.email == user_credentials.email).first()

    if not user:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"Invalid Credentials")

    # Password Verification
    if not utils.verify(user_credentials.password, user.password):
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=f"Invalid Credentials")
```

Next steps would be:

* Create Token
* Return Token


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.arkannis.net/programming/python/frameworks/fastapi/login-process.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
