> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/go-gitea/gitea/llms.txt
> Use this file to discover all available pages before exploring further.

# OAuth2 Provider

> Use Gitea as an OAuth2 provider for Single Sign-On (SSO) and third-party application authentication

## Overview

Gitea can act as an OAuth2 provider, allowing you to use your Gitea account to authenticate with third-party applications and services. This enables Single Sign-On (SSO) capabilities and allows developers to build applications that integrate with Gitea.

## OAuth2 Concepts

### Client Types

Gitea supports two types of OAuth2 clients as defined in [RFC 6749](https://datatracker.ietf.org/doc/html/rfc6749):

* **Confidential Clients** - Applications that can securely store client secrets (server-side apps)
* **Public Clients** - Applications that cannot securely store secrets (mobile apps, SPAs)

Reference: `models/auth/oauth2.go:43-48`

### Grant Types

Gitea supports the following OAuth2 grant flows:

* **Authorization Code** - Most common flow for web applications
* **Refresh Token** - Obtain new access tokens without re-authentication
* **Client Credentials** - Machine-to-machine authentication

### Token Types

Gitea issues two types of tokens:

* **Access Token** - Short-lived token (default expiry varies) for API access
* **Refresh Token** - Long-lived token to obtain new access tokens

Reference: `services/oauth2_provider/token.go:18-26`

## Creating an OAuth2 Application

<Steps>
  ### Navigate to settings

  1. Click on your profile avatar in the top-right corner
  2. Select **Settings**
  3. Click **Applications** in the sidebar

  ### Register a new application

  1. Click **Create a new OAuth2 Application**
  2. Fill in the application details:
     * **Application Name**: Descriptive name for your application
     * **Redirect URIs**: One or more authorized callback URLs (one per line)
     * **Confidential Client**: Check if the application can securely store secrets
     * **Skip Authorization**: Skip secondary authorization prompt for trusted apps

  ### Save credentials

  After creating the application, you'll receive:

  * **Client ID**: Public identifier for your application
  * **Client Secret**: Secret key for confidential clients (store securely!)

  <Warning>
    The client secret is only shown once. Store it securely - if lost, you'll need to regenerate it.
  </Warning>
</Steps>

## Authorization Code Flow

The authorization code flow is the recommended approach for web applications.

### Step 1: Authorization Request

Redirect users to Gitea's authorization endpoint:

```http theme={null}
GET https://gitea.example.com/login/oauth/authorize?client_id=CLIENT_ID&redirect_uri=REDIRECT_URI&response_type=code&state=RANDOM_STATE
```

**Parameters:**

* `client_id` (required) - Your application's client ID
* `redirect_uri` (required) - Must match a registered redirect URI
* `response_type` (required) - Must be `code`
* `state` (recommended) - Random string to prevent CSRF attacks
* `scope` (optional) - Space-separated list of requested scopes

### Step 2: User Authorization

The user will be prompted to authorize your application. After approval, they're redirected to:

```http theme={null}
https://your-app.com/callback?code=AUTHORIZATION_CODE&state=RANDOM_STATE
```

### Step 3: Exchange Code for Token

Exchange the authorization code for an access token:

```bash theme={null}
curl -X POST "https://gitea.example.com/login/oauth/access_token" \
  -H "Content-Type: application/json" \
  -d '{
    "client_id": "YOUR_CLIENT_ID",
    "client_secret": "YOUR_CLIENT_SECRET",
    "code": "AUTHORIZATION_CODE",
    "grant_type": "authorization_code",
    "redirect_uri": "https://your-app.com/callback"
  }'
```

**Response:**

```json theme={null}
{
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
```

### Step 4: Use Access Token

Include the access token in API requests:

```bash theme={null}
curl "https://gitea.example.com/api/v1/user" \
  -H "Authorization: Bearer ACCESS_TOKEN"
```

## Token Structure

Gitea uses JWT (JSON Web Tokens) for OAuth2 tokens. The token structure includes:

```go theme={null}
type Token struct {
    GrantID int64     // Grant identifier
    Kind    TokenKind // Access or refresh token
    Counter int64     // Token counter for refresh tokens
    jwt.RegisteredClaims
}
```

Reference: `services/oauth2_provider/token.go:28-34`

### Token Validation

Tokens are validated using the configured JWT signing method:

```go theme={null}
// Parse and validate token
token, err := ParseToken(jwtToken, signingKey)
if err != nil {
    return nil, err
}
```

Reference: `services/oauth2_provider/token.go:36-56`

## Refresh Tokens

When an access token expires, use the refresh token to obtain a new one:

```bash theme={null}
curl -X POST "https://gitea.example.com/login/oauth/access_token" \
  -H "Content-Type: application/json" \
  -d '{
    "client_id": "YOUR_CLIENT_ID",
    "client_secret": "YOUR_CLIENT_SECRET",
    "grant_type": "refresh_token",
    "refresh_token": "REFRESH_TOKEN"
  }'
```

**Response:**

```json theme={null}
{
  "access_token": "NEW_ACCESS_TOKEN",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "NEW_REFRESH_TOKEN"
}
```

<Note>
  Each refresh invalidates the previous refresh token and issues a new one.
</Note>

## OpenID Connect (OIDC)

Gitea supports OpenID Connect, an identity layer on top of OAuth2.

### ID Token Structure

```go theme={null}
type OIDCToken struct {
    jwt.RegisteredClaims
    Nonce string // Nonce for request validation
    
    // Profile scope
    Name              string
    PreferredUsername string
    Profile           string
    Picture           string
    Website           string
    Locale            string
    UpdatedAt         timeutil.TimeStamp
    
    // Email scope
    Email         string
    EmailVerified bool
    
    // Groups scope
    Groups []string // Generated from organizations and teams
}
```

Reference: `services/oauth2_provider/token.go:66-86`

### OIDC Discovery

Gitea exposes an OIDC discovery endpoint at:

```http theme={null}
GET https://gitea.example.com/.well-known/openid-configuration
```

This endpoint provides metadata about the OIDC provider, including:

* Authorization endpoint
* Token endpoint
* Supported scopes
* Supported response types
* JWKs endpoint

### Requesting ID Tokens

Add `openid` to the scope parameter:

```http theme={null}
GET https://gitea.example.com/login/oauth/authorize
  ?client_id=CLIENT_ID
  &redirect_uri=REDIRECT_URI
  &response_type=code
  &scope=openid%20profile%20email
  &state=RANDOM_STATE
```

The token response will include an `id_token` field:

```json theme={null}
{
  "access_token": "...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "...",
  "id_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
```

## OAuth2 Scopes

Gitea supports the following OAuth2 scopes:

| Scope               | Description                             |
| ------------------- | --------------------------------------- |
| `repo`              | Full access to repositories             |
| `repo:status`       | Access to commit status                 |
| `public_repo`       | Access to public repositories           |
| `admin:org`         | Full control of organizations           |
| `write:org`         | Read and write access to organizations  |
| `read:org`          | Read-only access to organizations       |
| `admin:public_key`  | Full control of public keys             |
| `write:public_key`  | Create, update, delete public keys      |
| `read:public_key`   | Read public keys                        |
| `admin:repo_hook`   | Full control of repository hooks        |
| `write:repo_hook`   | Create, update, delete repository hooks |
| `read:repo_hook`    | Read repository hooks                   |
| `admin:org_hook`    | Full control of organization hooks      |
| `user`              | Read and write access to user profile   |
| `read:user`         | Read user profile data                  |
| `user:email`        | Read user email addresses               |
| `user:follow`       | Follow and unfollow users               |
| `delete_repo`       | Delete repositories                     |
| `package`           | Access to packages                      |
| `admin:gpg_key`     | Full control of GPG keys                |
| `write:gpg_key`     | Create, update, delete GPG keys         |
| `read:gpg_key`      | Read GPG keys                           |
| `admin:application` | Full control of applications            |
| `write:application` | Create, update, delete applications     |
| `read:application`  | Read applications                       |

### OpenID Connect Scopes

| Scope     | Description                      | Claims                                                                                |
| --------- | -------------------------------- | ------------------------------------------------------------------------------------- |
| `openid`  | Required for OIDC                | `sub`                                                                                 |
| `profile` | User profile information         | `name`, `preferred_username`, `profile`, `picture`, `website`, `locale`, `updated_at` |
| `email`   | User email address               | `email`, `email_verified`                                                             |
| `groups`  | Organization and team membership | `groups`                                                                              |

## Built-in Applications

Gitea includes several built-in OAuth2 applications for common Git tools:

### Git Credential Manager

* **Client ID**: `e90ee53c-94e2-48ac-9358-a874fb9e0662`
* **Redirect URIs**: `http://127.0.0.1`, `https://127.0.0.1`
* **Purpose**: Microsoft's Git Credential Manager

Reference: `models/auth/oauth2.go:73-77`

### git-credential-oauth

* **Client ID**: `a4792ccc-144e-407e-86c9-5e7d8d9c3269`
* **Redirect URIs**: `http://127.0.0.1`, `https://127.0.0.1`
* **Purpose**: git-credential-oauth helper

Reference: `models/auth/oauth2.go:68-72`

### Tea CLI

* **Client ID**: `d57cb8c4-630c-4168-8324-ec79935e18d4`
* **Redirect URIs**: `http://127.0.0.1`, `https://127.0.0.1`
* **Purpose**: Tea command-line client

Reference: `models/auth/oauth2.go:78-82`

These applications can be enabled in your `app.ini`:

```ini theme={null}
[oauth2]
DEFAULT_APPLICATIONS = git-credential-oauth, git-credential-manager, tea
```

## Security Best Practices

### State Parameter

Always use the `state` parameter to prevent CSRF attacks:

```javascript theme={null}
// Generate random state
const state = crypto.randomBytes(32).toString('hex');

// Store in session
session.oauthState = state;

// Include in authorization URL
const authUrl = `https://gitea.example.com/login/oauth/authorize
  ?client_id=${clientId}
  &redirect_uri=${redirectUri}
  &response_type=code
  &state=${state}`;

// Verify on callback
if (req.query.state !== session.oauthState) {
  throw new Error('Invalid state parameter');
}
```

### Client Secret Protection

* Never expose client secrets in client-side code
* Store secrets in environment variables or secure vaults
* Use confidential client type for server-side applications
* Rotate secrets regularly
* Use public client type for applications that can't store secrets

### Redirect URI Validation

Gitea performs exact matching on redirect URIs:

```go theme={null}
func (app *OAuth2Application) ContainsRedirectURI(redirectURI string) bool {
    // OAuth2 requires exact match, no dynamic parts allowed
    return slices.Contains(app.RedirectURIs, redirectURI)
}
```

Reference: `models/auth/oauth2.go:147-150`

* Always use HTTPS redirect URIs in production
* Register all valid redirect URIs
* Never use wildcards in redirect URIs
* Avoid open redirects

### Token Storage

* Store access tokens securely (encrypted storage, secure cookies)
* Never log or transmit tokens in plain text
* Implement token rotation
* Clear tokens on logout

## Authorization Code Expiry

Authorization codes are short-lived and expire after 10 minutes per [RFC 6749](https://datatracker.ietf.org/doc/html/rfc6749#section-4.1.2):

```go theme={null}
const oauth2AuthorizationCodeValidity = 10 * time.Minute
```

Reference: `models/auth/oauth2.go:31-32`

Codes can only be used once. Attempting to reuse a code will result in an error.

## Revoking Access

Users can revoke application access at any time:

<Steps>
  ### Navigate to authorized applications

  1. Go to **Settings** > **Applications**
  2. Click on the **Authorized OAuth Apps** tab

  ### Revoke access

  1. Find the application you want to revoke
  2. Click **Revoke** next to the application
  3. Confirm the revocation
</Steps>

Revoking access invalidates all tokens issued to that application for your account.

## Testing OAuth2 Flow

You can test the OAuth2 flow using curl:

```bash theme={null}
# 1. Get authorization code (opens browser)
open "https://gitea.example.com/login/oauth/authorize?client_id=YOUR_CLIENT_ID&redirect_uri=http://localhost:8080/callback&response_type=code&state=random123"

# 2. Exchange code for token (after getting code from callback)
curl -X POST "https://gitea.example.com/login/oauth/access_token" \
  -H "Content-Type: application/json" \
  -d '{
    "client_id": "YOUR_CLIENT_ID",
    "client_secret": "YOUR_CLIENT_SECRET",
    "code": "AUTHORIZATION_CODE",
    "grant_type": "authorization_code",
    "redirect_uri": "http://localhost:8080/callback"
  }'

# 3. Use access token
curl "https://gitea.example.com/api/v1/user" \
  -H "Authorization: Bearer ACCESS_TOKEN"
```

## Common Use Cases

### Single Sign-On (SSO)

Use Gitea as an identity provider for your organization's applications:

1. Register your application as an OAuth2 client
2. Implement the authorization code flow
3. Use OIDC for user profile information
4. Map Gitea organizations/teams to application roles

### CI/CD Integration

Authenticate CI/CD pipelines using OAuth2:

1. Create a confidential client for your CI/CD system
2. Use client credentials grant for machine-to-machine auth
3. Scope tokens to minimum required permissions
4. Rotate tokens regularly

### Mobile Applications

Authenticate mobile apps using OAuth2:

1. Create a public client (no client secret)
2. Use authorization code flow with PKCE
3. Store tokens securely in device keychain
4. Implement token refresh on app launch

### Third-Party Integrations

Integrate with external services:

1. Create an OAuth2 application
2. Configure the service to use Gitea as OAuth2 provider
3. Map Gitea scopes to service permissions
4. Test the integration flow

## Troubleshooting

### Invalid Redirect URI

**Error**: `redirect_uri_mismatch`

**Solution**: Ensure the redirect URI in the authorization request exactly matches one registered in the application settings.

### Invalid Client

**Error**: `invalid_client`

**Solution**: Verify that the client ID and client secret are correct.

### Expired Authorization Code

**Error**: `invalid_grant`

**Solution**: Authorization codes expire after 10 minutes. Request a new authorization code.

### Invalid Token

**Error**: `invalid_token`

**Solution**: The access token may have expired. Use the refresh token to obtain a new access token.

## Further Reading

* [OAuth 2.0 RFC 6749](https://datatracker.ietf.org/doc/html/rfc6749)
* [OpenID Connect Core 1.0](https://openid.net/specs/openid-connect-core-1_0.html)
* [OAuth 2.0 Security Best Practices](https://datatracker.ietf.org/doc/html/draft-ietf-oauth-security-topics)
