The Login Endpoint
Add a POST /login endpoint that verifies credentials and returns a JWT
Writing code and entering commands is only available on desktop. Open this page on a larger screen to complete this chapter.
From registration to login
Registration creates the account. Login verifies the credentials and hands back a token. The login endpoint takes the same email and password, but instead of storing a new user, it looks up an existing one and checks the password.
Why the error message is vague
When login fails, the endpoint returns "Invalid email or password" — the same message whether the email does not exist or the password is wrong. This is intentional. A specific message like "Email not found" tells an attacker which emails exist in your database. A vague message reveals nothing.
Two new imports from auth
The login endpoint uses two functions from auth.py that you have not imported yet: verify_password checks the plain password against the stored hash, and create_access_token generates the JWT. You will add both to the existing auth import line.
Instructions
Add a login endpoint to main.py.
- Update the auth import to include the two new functions you need:
from auth import User, hash_password, verify_password, create_access_token. - Define the login endpoint with
@app.post("/login")anddef login(user_data: UserCreate, session: SessionDep):— it reusesUserCreatesince login takes the same email and password fields as registration. - Look up the user by email:
user = session.exec(select(User).where(User.email == user_data.email)).first()— if no account exists with this email,userwill beNone. - Check both failure cases in one condition: if
userisNoneorverify_password(user_data.password, user.password_hash)returnsFalse, raiseHTTPException(status_code=401, detail="Invalid email or password"). This handles both "email not found" and "wrong password" with the same vague message — as explained in the content above, you do not want to reveal which one failed. - If the credentials are valid, generate a JWT:
token = create_access_token(user.email)— this calls the function you built in Lesson 1 that signs the user's email into a 30-minute token. - Return
{"access_token": token, "token_type": "bearer"}— this is the standard OAuth2 response format. The"token_type": "bearer"tells the client to send the token in anAuthorization: Bearerheader.
Interactive Code Editor
Sign in to write and run code, track your progress, and unlock all chapters.
Sign In to Start Coding