# How to Troubleshoot Gitea Authentication Issues: A Complete Technical Guide

> Troubleshoot Gitea authentication issues by enabling trace logging, verifying credential flows in services/auth/auth.go, and inspecting token parsing in oauth2.go. Resolve path detection, validation, or session persistence fail...

- Repository: [Gitea/gitea](https://github.com/go-gitea/gitea)
- Tags: how-to-guide
- Published: 2026-03-07

---

**To troubleshoot Gitea authentication issues, enable trace logging to capture the `authPathDetector` evaluation, verify credential flows through the pluggable auth methods in [`services/auth/auth.go`](https://github.com/go-gitea/gitea/blob/main/services/auth/auth.go), and inspect token parsing logic in [`oauth2.go`](https://github.com/go-gitea/gitea/blob/main/oauth2.go) to isolate failures in path detection, validation, or session persistence.**

Gitea’s authentication system relies on a **pluggable "auth method" framework** that processes requests through a structured detection and validation pipeline. When users report login failures or API access denials, understanding the internal flow—from path detection in [`services/auth/auth.go`](https://github.com/go-gitea/gitea/blob/main/services/auth/auth.go) to token parsing in [`oauth2.go`](https://github.com/go-gitea/gitea/blob/main/oauth2.go)—is essential for rapid diagnosis. This guide provides a source-code-backed approach to identify and resolve authentication failures in the `go-gitea/gitea` repository.

## Understanding Gitea's Authentication Architecture

### Path Detection and Protected Routes

In [`services/auth/auth.go`](https://github.com/go-gitea/gitea/blob/main/services/auth/auth.go), the `newAuthPathDetector` function examines incoming HTTP requests to determine if authentication is required. The detector returns `true` for protected paths including API endpoints, Git raw content, archives, attachments, and feeds (lines 63-80). If the detector misidentifies a path as public, the request bypasses authentication entirely.

### Auth Method Selection and Verification

Once a path is flagged for protection, Gitea iterates through registered `auth.Method` implementations until one returns a valid user. These methods include password-based, LDAP, SMTP, OAuth2, WebAuthn, and token-based API authentication. Each method implements its own credential validation logic in the `services/auth/source/` directory.

### Session Management and Regeneration

Successful authentication triggers `handleSignIn` (lines 23-64 in [`auth.go`](https://github.com/go-gitea/gitea/blob/main/auth.go)), which regenerates the session ID to prevent fixation attacks. This function stores the user ID, username, and language preferences, while clearing stale WebAuthn assertion data. Failures here typically manifest as "Error regenerating session" messages in the logs.

## Common Authentication Failure Points

- **Invalid credentials (password, LDAP, SMTP)**: Occurs when passwords mismatch, accounts are disabled, or external sources fail to connect. Check [`services/auth/source/ldap/source_authenticate.go`](https://github.com/go-gitea/gitea/blob/main/services/auth/source/ldap/source_authenticate.go) and corresponding SMTP authentication handlers to verify bind DN settings and TLS configurations.

- **API token rejected**: Results from missing tokens, expired grants, or `DISABLE_QUERY_AUTH_TOKEN` being set to `true` while clients still transmit tokens via query strings. Inspect the `parseToken` function in [`services/auth/oauth2.go`](https://github.com/go-gitea/gitea/blob/main/services/auth/oauth2.go) (lines 84-98) to confirm token extraction logic.

- **OAuth2 login failures**: Stems from provider misconfiguration (client ID/secret mismatches), invalid redirect URLs, or JWT signature verification failures. The `GetOAuthAccessTokenScopeAndUserID` function (lines 40-55 in [`oauth2.go`](https://github.com/go-gitea/gitea/blob/main/oauth2.go)) validates token signatures and expiration claims.

- **WebAuthn/2FA failures**: Caused by missing assertions, incorrect FIDO2 device registration, or lost session cookies. Note that `handleSignIn` explicitly clears `webauthnAssertion` data during sign-in, requiring clients to maintain persistent session cookies.

- **Git raw/attachment 401 errors**: Happens when `authPathDetector` fails to recognize paths as authenticated resources. Verify `isGitRawOrAttachPath` and `isArchivePath` methods (lines 96-112 in [`auth.go`](https://github.com/go-gitea/gitea/blob/main/auth.go)) if protected assets return unexpected 401 status codes.

- **Session regeneration errors**: Indicate underlying storage failures in Redis, memory, or file-based session stores when `session.RegenerateSession` cannot create new session IDs.

- **Feed authentication disabled**: Occurs when `setting.Other.EnableFeed` is `false` but clients attempt to access RSS/Atom endpoints. Check `authPathDetector.isFeedRequest` (lines 82-90 in [`auth.go`](https://github.com/go-gitea/gitea/blob/main/auth.go)).

## Step-by-Step Troubleshooting Checklist

1. **Enable detailed logging**: Set `APP_LOG_LEVEL=trace` in [`app.ini`](https://github.com/go-gitea/gitea/blob/main/app.ini) and restart Gitea. Monitor output from `modules/log` for `Trace`, `Warn`, and `Error` entries during authentication attempts.

2. **Verify auth source configuration**: Review `[auth]` sections in [`app.ini`](https://github.com/go-gitea/gitea/blob/main/app.ini) (e.g., `[ldap]`, `[smtp]`). Confirm host, port, bind DN, TLS settings, and network connectivity between Gitea and external authentication servers.

3. **Validate OAuth2 settings**: Inspect the `[oauth2]` section for `CLIENT_ID`, `CLIENT_SECRET`, and `JWT_SECRET` mismatches. Ensure signing keys align with external provider configurations.

4. **Inspect token contents**: Decode JWT tokens using standard JWT debuggers to verify `exp`, `iat`, and `grant_id` claims without requiring the signing secret.

5. **Query the database directly**:
   - Check `access_token` table for API tokens: `SELECT * FROM access_token WHERE sha256 = ...`
   - Verify OAuth grants in `oauth2_grant`: `SELECT * FROM oauth2_grant WHERE id = ...`
   - Confirm user status in `user` table: `is_active`, `login_type`, and `login_source` columns

6. **Verify session persistence**: Ensure the `i_like_gitea` cookie (or the name specified in `setting.CookieUsername`) accompanies every request. Validate that the session store (memory, Redis, or file) has write permissions and adequate storage.

7. **Test request paths manually**: Use `curl -v` to examine endpoints, observing returned status codes and `WWW-Authenticate` headers for detailed rejection reasons.

8. **Run integration tests**: Execute `make test-integration` to exercise LDAP, OAuth2, and token authentication paths via [`tests/integration/auth_ldap_test.go`](https://github.com/go-gitea/gitea/blob/main/tests/integration/auth_ldap_test.go) and [`oauth_test.go`](https://github.com/go-gitea/gitea/blob/main/oauth_test.go).

## Debugging with Code Examples

### Manually Parsing Tokens from HTTP Requests

When debugging API authentication, you can replicate Gitea's internal token extraction logic:

```go
// Re-use Gitea's internal helper – it respects DISABLE_QUERY_AUTH_TOKEN.
token, ok := parseToken(req)
if !ok {
    // No token found – authentication will be skipped for this request.
}

```

*Reference*: `parseToken` in [`services/auth/oauth2.go`](https://github.com/go-gitea/gitea/blob/main/services/auth/oauth2.go) (lines 84-100).

### Forcing Session Regeneration After Password Changes

To manually regenerate sessions during custom authentication workflows:

```go
// Regenerate the session (same logic as handleSignIn)
newSess, err := session.RegenerateSession(w, r)
if err != nil {
    log.Error("Failed to regenerate session: %v", err)
}
sess = newSess
sess.Set("uid", user.ID)
sess.Set("uname", user.Name)

```

*Reference*: `handleSignIn` in [`services/auth/auth.go`](https://github.com/go-gitea/gitea/blob/main/services/auth/auth.go) (lines 23-45).

### Decoding OAuth2 JWT Access Tokens for Debugging

For troubleshooting OAuth2 token validation:

```go
import "code.gitea.io/gitea/services/oauth2_provider"

func decodeAccessToken(tokenStr string) {
    token, err := oauth2_provider.ParseToken(tokenStr, oauth2_provider.DefaultSigningKey)
    if err != nil {
        log.Error("Invalid JWT: %v", err)
        return
    }
    log.Info("GrantID=%d, Owner=%d, Scope=%s", token.GrantID, token.OwnerID, token.Scope)
}

```

*Reference*: Token parsing in `GetOAuthAccessTokenScopeAndUserID` (lines 40-55 in [`oauth2.go`](https://github.com/go-gitea/gitea/blob/main/oauth2.go)).

### Checking Whether a Request Requires Authentication

To verify if a specific endpoint triggers authentication checks:

```go
detector := newAuthPathDetector(req)
if detector.isAPIPath() || detector.isGitRawOrAttachPath() ||
   detector.isArchivePath() || detector.isAttachmentDownload() {
    // Authentication required – invoke the appropriate auth method.
}

```

*Reference*: `authPathDetector` methods in [`services/auth/auth.go`](https://github.com/go-gitea/gitea/blob/main/services/auth/auth.go) (lines 63-112).

## Key Source Files for Authentication Debugging

Understanding these core files accelerates troubleshooting:

- **[`services/auth/auth.go`](https://github.com/go-gitea/gitea/blob/main/services/auth/auth.go)**: Contains `newAuthPathDetector`, `handleSignIn`, and the core authentication orchestration logic.
- **[`services/auth/oauth2.go`](https://github.com/go-gitea/gitea/blob/main/services/auth/oauth2.go)**: Implements `parseToken` and `GetOAuthAccessTokenScopeAndUserID` for OAuth2 and API token validation.
- **[`services/auth/source/ldap/source_authenticate.go`](https://github.com/go-gitea/gitea/blob/main/services/auth/source/ldap/source_authenticate.go)**: Handles LDAP bind operations and directory authentication.
- **[`services/auth/source/smtp/auth.go`](https://github.com/go-gitea/gitea/blob/main/services/auth/source/smtp/auth.go)**: Manages email-based authentication workflows.
- **[`modules/auth/httpauth/httpauth.go`](https://github.com/go-gitea/gitea/blob/main/modules/auth/httpauth/httpauth.go)**: Provides `Authorization` header parsing for Bearer and Basic schemes.
- **[`modules/session/session.go`](https://github.com/go-gitea/gitea/blob/main/modules/session/session.go)**: Abstracts session regeneration and storage mechanisms.
- **[`models/auth/access_token.go`](https://github.com/go-gitea/gitea/blob/main/models/auth/access_token.go)**: Database model for API token persistence and SHA256 hashing.
- **[`models/auth/oauth2_grant.go`](https://github.com/go-gitea/gitea/blob/main/models/auth/oauth2_grant.go)**: Stores OAuth2 grant relationships and token metadata.
- **[`routers/web/auth/oauth.go`](https://github.com/go-gitea/gitea/blob/main/routers/web/auth/oauth.go)**: Web interface OAuth2 flow handlers for sign-in and callbacks.
- **[`routers/web/auth/auth.go`](https://github.com/go-gitea/gitea/blob/main/routers/web/auth/auth.go)**: Generic login page processing for password, LDAP, and SMTP methods.

## Summary

- **Gitea uses a pluggable auth framework** with `authPathDetector` determining which requests require authentication based on URL patterns in [`services/auth/auth.go`](https://github.com/go-gitea/gitea/blob/main/services/auth/auth.go).
- **Token validation occurs in [`oauth2.go`](https://github.com/go-gitea/gitea/blob/main/oauth2.go)**, where `parseToken` extracts credentials from headers or query strings, respecting the `DISABLE_QUERY_AUTH_TOKEN` setting.
- **Session regeneration happens in `handleSignIn`**, which clears WebAuthn data and creates new session IDs to prevent fixation attacks.
- **LDAP and SMTP failures** typically stem from connection issues or bind DN misconfigurations in `services/auth/source/` directories.
- **Database verification** of `access_token`, `oauth2_grant`, and `user` tables often reveals account status or token expiration issues.
- **Trace logging** via `APP_LOG_LEVEL=trace` provides visibility into the authentication decision chain.

## Frequently Asked Questions

### Why does my API token work in the header but not in the query string?

Gitea respects the `DISABLE_QUERY_AUTH_TOKEN` setting in [`app.ini`](https://github.com/go-gitea/gitea/blob/main/app.ini). When enabled, the `parseToken` function in [`services/auth/oauth2.go`](https://github.com/go-gitea/gitea/blob/main/services/auth/oauth2.go) (lines 84-98) ignores tokens passed as query parameters for security reasons. Use the `Authorization: Bearer <token>` header instead, which is always evaluated regardless of this setting.

### How does Gitea decide which requests need authentication?

The `newAuthPathDetector` function in [`services/auth/auth.go`](https://github.com/go-gitea/gitea/blob/main/services/auth/auth.go) (lines 63-80) evaluates URL paths against patterns for API endpoints, Git raw content, archives, attachments, and feeds. If a path matches protected patterns, Gitea iterates through registered auth methods until one validates the request, otherwise returning 401 or 403 responses.

### What causes "Error regenerating session" during login?

This error originates from `handleSignIn` in [`services/auth/auth.go`](https://github.com/go-gitea/gitea/blob/main/services/auth/auth.go) when `session.RegenerateSession` fails. Common causes include full disk space (for file-based sessions), Redis connection failures, or permission issues on session storage directories. Verify that your configured session store (memory, file, or Redis) is accessible and writable by the Gitea process.

### Why does OAuth2 authentication fail with valid credentials?

OAuth2 failures typically occur in `GetOAuthAccessTokenScopeAndUserID` (lines 40-55 in [`oauth2.go`](https://github.com/go-gitea/gitea/blob/main/oauth2.go)) due to JWT signature mismatches, expired tokens, or incorrect `JWT_SECRET` configurations in [`app.ini`](https://github.com/go-gitea/gitea/blob/main/app.ini). Verify that the `[oauth2]` section's `JWT_SECRET` matches between Gitea and your OAuth2 provider, and decode the token to confirm the `exp` claim has not passed.