Skip to content

Implement user authentication with JWT, including login and registration features#52

Open
Davictory2003 wants to merge 5 commits intomainfrom
database
Open

Implement user authentication with JWT, including login and registration features#52
Davictory2003 wants to merge 5 commits intomainfrom
database

Conversation

@Davictory2003
Copy link
Copy Markdown
Contributor

No description provided.

Copilot AI review requested due to automatic review settings April 20, 2026 18:36
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Adds JWT-based authentication (login/registration/token refresh) across the Django backend and React frontend, wiring routing + an auth context provider so the UI can log in/out and display the current user.

Changes:

  • Introduce an AuthContext in the frontend with login/register/logout and periodic token refresh
  • Add /api/token/, /api/token/refresh/, and /api/register/ endpoints backed by SimpleJWT + a user serializer
  • Update the app shell to use React Router routes and show auth controls in the header

Reviewed changes

Copilot reviewed 12 out of 13 changed files in this pull request and generated 10 comments.

Show a summary per file
File Description
frontend/src/main.jsx Wraps the app with BrowserRouter and AuthProvider
frontend/src/context/AuthContext.jsx Adds auth state management, JWT decode, token refresh, and auth actions
frontend/src/components/Login.jsx Adds login form wired to AuthContext
frontend/src/components/SignUp.jsx Adds registration form wired to AuthContext
frontend/src/App.jsx Adds routes for login/signup and header auth UI
frontend/src/App.css Adjusts .btn styling and hover behavior (used by auth links/buttons)
frontend/package.json Adds jwt-decode and react-router-dom dependencies
backend/requirements.txt Adds djangorestframework-simplejwt
backend/cheat_sheet/settings.py Enables JWTAuthentication in DRF settings
backend/api/views.py Adds custom token view and registration view
backend/api/urls.py Exposes token, refresh, and register endpoints
backend/api/serializers.py Adds user serializer and custom token claims
Files not reviewed (1)
  • frontend/package-lock.json: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread frontend/src/context/AuthContext.jsx Outdated
Comment on lines +10 to +15
const [authTokens, setAuthTokens] = useState(() =>
localStorage.getItem('authTokens') ? JSON.parse(localStorage.getItem('authTokens')) : null
);
const [user, setUser] = useState(() =>
localStorage.getItem('authTokens') ? jwtDecode(localStorage.getItem('authTokens')) : null
);
Comment thread frontend/src/context/AuthContext.jsx Outdated
Comment on lines +21 to +31
const response = await fetch('/api/token/', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ username, password }),
});

const data = await response.json();

if (response.status === 200) {
Comment on lines +55 to +62
if (response.status === 201) {
// Auto login after registration
loginUser(username, password);
} else {
const data = await response.json();
const errorMessage = typeof data === 'object' ? JSON.stringify(data) : 'Registration failed';
alert(`Registration failed: ${errorMessage}`);
}
Comment thread frontend/src/context/AuthContext.jsx Outdated
if (response.status === 200) {
setAuthTokens(data);
setUser(jwtDecode(data.access));
localStorage.setItem('authTokens', JSON.stringify(data));
Comment thread frontend/src/context/AuthContext.jsx Outdated
const logoutUser = () => {
setAuthTokens(null);
setUser(null);
localStorage.removeItem('authTokens');
navigate('/login');
}
} catch (err) {
console.error('Token refresh failed', err);
"rest_framework_simplejwt.authentication.JWTAuthentication",
),
"DEFAULT_PERMISSION_CLASSES": [
"rest_framework.permissions.AllowAny",
Comment thread backend/api/urls.py Outdated
Comment thread frontend/src/components/Login.jsx Outdated
Comment on lines +20 to +27
<label style={{ display: 'block', marginBottom: '0.5rem', fontWeight: 500, color: 'var(--text)' }}>Username</label>
<input
type="text"
placeholder="Enter your username"
value={username}
onChange={(e) => setUsername(e.target.value)}
className="input-field"
required
Comment thread frontend/src/components/SignUp.jsx Outdated
Comment on lines +20 to +37
<label style={{ display: 'block', marginBottom: '0.5rem', fontWeight: 500, color: 'var(--text)' }}>Username</label>
<input
type="text"
placeholder="Choose a username"
value={username}
onChange={(e) => setUsername(e.target.value)}
className="input-field"
required
style={{ marginBottom: 0 }}
/>
</div>
<div>
<label style={{ display: 'block', marginBottom: '0.5rem', fontWeight: 500, color: 'var(--text)' }}>Password</label>
<input
type="password"
placeholder="Choose a password"
value={password}
onChange={(e) => setPassword(e.target.value)}
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@Davictory2003
Copy link
Copy Markdown
Contributor Author

@copilot apply changes based on the comments in this thread

Copilot AI and others added 2 commits April 20, 2026 20:00
…rmissions

Agent-Logs-Url: https://github.com/ChicoState/cheat-sheet/sessions/c698eda3-f6c3-4ef7-ae11-c8fae0da2fd9

Co-authored-by: Davictory2003 <68972845+Davictory2003@users.noreply.github.com>
…ndly registration errors

Agent-Logs-Url: https://github.com/ChicoState/cheat-sheet/sessions/c698eda3-f6c3-4ef7-ae11-c8fae0da2fd9

Co-authored-by: Davictory2003 <68972845+Davictory2003@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 20, 2026

@copilot apply changes based on the comments in this thread

Applied all changes from the review thread (commits 80532e4 and e9ef289):

AuthContext.jsx:

  • Fixed jwtDecode being called on the raw JSON string — now tokens are stored in-memory (React state only, no localStorage) to eliminate the XSS exposure; jwtDecode is only called on the data.access string
  • Added .catch(() => ({ detail: 'Invalid server response' })) defensive parsing on all response.json() calls so non-JSON error responses don't throw
  • loginUser is now await-ed inside registerUser (was fire-and-forget)
  • Registration error messages now format API field errors into human-readable text (e.g. username: A user with that username already exists.) instead of raw JSON.stringify
  • On token refresh exception, auth state is now cleared and user is navigated to /login instead of silently retrying

settings.py / views.py:

  • Default DRF permission changed to IsAuthenticated; health_check gets explicit @permission_classes([AllowAny]); RegisterView and SimpleJWT views already manage their own permissions

Login.jsx / SignUp.jsx:

  • All <label> elements now have htmlFor tied to matching id on <input>, plus autoComplete attributes (username, current-password, new-password)

tests.py:

  • Added auth_client fixture using force_authenticate; all 40 tests pass under the new IsAuthenticated default

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Implements JWT-based authentication (login + registration) across the Django REST backend and the React frontend, introducing routing/auth context on the client and SimpleJWT endpoints/permissions on the server.

Changes:

  • Frontend: add AuthContext provider, login/signup pages, and React Router routes/navigation.
  • Backend: enable SimpleJWT, add token + refresh + register endpoints, and switch DRF default permissions to authenticated-by-default.
  • Tests: update API tests to authenticate requests via a new fixture.

Reviewed changes

Copilot reviewed 13 out of 14 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
frontend/src/main.jsx Wraps the app in React Router + AuthProvider.
frontend/src/context/AuthContext.jsx Adds JWT login/register/logout and periodic refresh logic.
frontend/src/components/Login.jsx New login form component.
frontend/src/components/SignUp.jsx New registration form component.
frontend/src/App.jsx Adds routes and header UI for auth actions.
frontend/src/App.css Updates .btn styling and hover behavior.
frontend/package.json Adds jwt-decode and react-router-dom.
frontend/package-lock.json Locks new frontend dependencies.
backend/requirements.txt Adds djangorestframework-simplejwt.
backend/cheat_sheet/settings.py Enables JWT auth + changes default permissions to IsAuthenticated.
backend/api/views.py Adds custom token view + register view; allows anonymous health check.
backend/api/urls.py Adds token/refresh/register routes.
backend/api/tests.py Adds authenticated client fixture; updates tests to use it.
backend/api/serializers.py Adds user registration serializer + custom token claims serializer.
Files not reviewed (1)
  • frontend/package-lock.json: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread frontend/src/context/AuthContext.jsx Outdated
const data = await response.json().catch(() => ({ detail: 'Invalid server response' }));

if (response.ok) {
setAuthTokens(data);
Comment thread backend/cheat_sheet/settings.py Outdated
),
"DEFAULT_PERMISSION_CLASSES": [
"rest_framework.permissions.AllowAny",
"rest_framework.permissions.IsAuthenticated",
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment thread frontend/src/App.jsx
Comment on lines +155 to +167
<Routes>
<Route path="/" element={
<CreateCheatSheet
initialData={cheatSheet}
onSave={handleSave}
onReset={handleReset}
isSaving={isSaving}
onCancel={() => {}}
/>
} />
<Route path="/login" element={<Login />} />
<Route path="/signup" element={<SignUp />} />
</Routes>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment thread backend/api/tests.py
Comment on lines +18 to +24
@pytest.fixture
def auth_client(db):
"""Authenticated API client (bypasses JWT for speed)."""
client = APIClient()
user = User.objects.create_user(username="testuser", password="testpass123")
client.force_authenticate(user=user)
return client
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment thread backend/api/urls.py
Comment on lines +15 to 18
path('register/', views.RegisterView.as_view(), name='register'),

path("health/", views.health_check, name="health-check"),
path("classes/", views.get_classes, name="get-classes"),
Comment on lines +17 to +27
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('id', 'username', 'password')
extra_kwargs = {'password': {'write_only': True}}

def create(self, validated_data):
user = User.objects.create_user(
username=validated_data['username'],
password=validated_data['password']
)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Davictory2003
Copy link
Copy Markdown
Contributor Author

@copilot apply changes based on the comments in this thread

…word validation, auth endpoint tests

Agent-Logs-Url: https://github.com/ChicoState/cheat-sheet/sessions/660affe3-e8c1-4d15-84ff-21145c2762ff

Co-authored-by: Davictory2003 <68972845+Davictory2003@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 21, 2026

@copilot apply changes based on the comments in this thread

Applied all changes from the review thread in commit d638d08:

  • AuthContext.jsx: Token refresh now merges response into existing state ({ ...prev, ...data }) to preserve the refresh token when SimpleJWT only returns a new access token
  • settings.py: Reverted default permission to AllowAny — the frontend hooks (formulas.js, latex.js, App.jsx) call core API endpoints without auth headers, so IsAuthenticated globally was causing 401s on all main flows; RegisterView keeps its own explicit AllowAny
  • App.jsx: Added a PrivateRoute component (uses Navigate from react-router-dom) that redirects unauthenticated users to /login; the / route is now wrapped with it
  • tests.py: Added TestRegisterEndpoint and TestTokenEndpoints covering registration success, duplicate username, weak/common password rejection, token obtain/refresh success, and invalid credential/token failures (8 new tests, 48 total pass)
  • urls.py: Removed trailing whitespace and extra blank lines inside urlpatterns
  • serializers.py: Added validate_password field validator to UserSerializer that enforces all configured AUTH_PASSWORD_VALIDATORS and returns 400 with field-level errors on failure

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants