Authorization failed over reverse proxy

Clean install Gitea v1.21.1 with the default docker-compose config from the docs

version: "3"

services:
  server:
    image: gitea/gitea:1.21.1
    ports:
      - "3000:3000"
      - "222:22"

If I configure Gitea to work from localhost (without the reverse proxy), I can clone a public or private repo, http or ssh.
I am redirected to the right authorization page, adding and verifying a ssh key works.

Working with the public and private repos with HTTP and SSH just works as intended.
I can create and delete ssh keys and applications, Gitea responds as I expect it to.

The problem

If I configure Gitea to work with the reverse proxy, I cannot access a private repo and I cannot verify or delete ssh keys or application tokens, so ssh doesn’t work either.

Nginx config taken from Gitea docs

## server listen 80 info here with redirect et all ##

server {
    listen 443 ssl;
    server_name git.example.org;
    ## lets encrypt certificate stuff here ##

    location / {
        client_max_body_size 512M;
        proxy_pass http://localhost:3000;
        proxy_set_header Connection $http_connection;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

HTTP
Public HTTPS repo works.
Private HTTPS repo opens a page to an authorization failed page
https://git.example.org/login/oauth/authorize?response_type=code&client_id=000&state=00000&code_challenge_method=S256&code_challenge=0000&redirect_uri=http%3a%2f%2f127.0.0.1%3a52589%2f *
image

Authorization failed

Client ID not registered

The authorization failed because we detected an invalid request. Please contact the maintainer of the app you have tried to authorize.

Nginx logs

0.0.0.0 - - [timedate] "POST /user/login HTTP/2.0" 303 0 "-" "browser info"
0.0.0.0 - - [timedate] "GET /login/oauth/authorize HTTP/2.0" 400 22352 "-" "browser info"
0.0.0.0 - - [timedate] "GET /avatar/d0aa75475ce02c63dbf2512d85cd4d2b?size=48 HTTP/2.0" 303 106 "-" "browser info"
0.0.0.0 - - [timedate] "GET /assets/js/eventsource.sharedworker.js?v=1.21.1 HTTP/2.0" 200 690 "-" "browser info"
0.0.0.0 - - [timedate] "GET /assets/img/favicon.svg HTTP/2.0" 200 1078 "-" "browser info"

Gitea container logs

timedate...eb/routing/logger.go:102:func1() [I] router: completed GET /Fluffy/test.git/info/refs for 0.0.0.0:0, 401 Unauthorized in 5.9ms @ repo/githttp.go:532(repo.GetInfoRefs)
timedate...rs/web/auth/oauth.go:828:handleAuthorizeError() [W] Authorization failed: Client ID not registered
timedate...eb/routing/logger.go:102:func1() [I] router: completed GET /login/oauth/authorize for 0.0.0.0:0, 400 Bad Request in 16.3ms @ auth/oauth.go:362(auth.AuthorizeOAuth)
timedate...eb/routing/logger.go:102:func1() [I] router: completed GET /avatar/d0aa75475ce02c63dbf2512d85cd4d2b for 108.162.241.74:0, 303 See Other in 9.3ms @ user/avatar.go:48(user.AvatarByEmailHash)
timedate...eb/routing/logger.go:102:func1() [I] router: completed GET /user/events for 0.0.0.0:0, 200 OK in 300029.7ms @ events/events.go:18(events.Events)
timedate...eb/routing/logger.go:68:func1() [I] router: polling   GET /user/events for 0.0.0.0:0, elapsed 3688.6ms @ events/events.go:18(events.Events)

SSH
After making ssh work over the reverse proxy (a pain) :
I cannot verify a ssh-key; the page url changes to https://git.example.org/user/settings/keys?verify_ssh=SHA256%0000 *, without showing the next step.

I also cannot delete ssh-keys or application tokens.
Clicking on “delete” brings me to a “404 undefined” page. Going back to the keys, they are still there.

One way or another I cannot clone a private repo from a clean install of gitea…

* 0000 instead of actual tokens or ips

Notice, if you are not using mount points or Docker volumes, you will lose all your data if you upgrade/change container because Docker is ephemeral. Containers are meant to be destroyed/wiped completely, only mount points/Docker volumes survive that wipe.

Can you post your app.ini file (scrub secrets before posting)?

I am not using a mount as long as I don’t have a working configuration, makes it faster to test new parameters to just delete and start over until it works.
I have a special mounting setup that demands specific permissions so I don’t want to work on that until I am certain I can make this work as it should :slight_smile:

here is a new clean app.ini after setup without reverse proxy

APP_NAME = Gitea: Git with a cup of tea
RUN_MODE = prod
RUN_USER = git
WORK_PATH = /data/gitea

[repository]
ROOT = /data/git/repositories

[repository.local]
LOCAL_COPY_PATH = /data/gitea/tmp/local-repo

[repository.upload]
TEMP_PATH = /data/gitea/uploads

[server]
APP_DATA_PATH = /data/gitea
DOMAIN = localhost
SSH_DOMAIN = localhost
HTTP_PORT = 3000
ROOT_URL = http://localhost:3000/
DISABLE_SSH = false
SSH_PORT = 222
SSH_LISTEN_PORT = 22
LFS_START_SERVER = true
LFS_JWT_SECRET = secret
OFFLINE_MODE = false

[database]
PATH = /data/gitea/gitea.db
DB_TYPE = sqlite3
HOST = localhost:3306
NAME = gitea
USER = root
PASSWD =
LOG_SQL = false
SCHEMA =
SSL_MODE = disable

[indexer]
ISSUE_INDEXER_PATH = /data/gitea/indexers/issues.bleve

[session]
PROVIDER_CONFIG = /data/gitea/sessions
PROVIDER = file

[picture]
AVATAR_UPLOAD_PATH = /data/gitea/avatars
REPOSITORY_AVATAR_UPLOAD_PATH = /data/gitea/repo-avatars

[attachment]
PATH = /data/gitea/attachments

[log]
MODE = console
LEVEL = info
ROOT_PATH = /data/gitea/log

[security]
INSTALL_LOCK = true
SECRET_KEY =
REVERSE_PROXY_LIMIT = 1
REVERSE_PROXY_TRUSTED_PROXIES = *
INTERNAL_TOKEN = token
PASSWORD_HASH_ALGO = pbkdf2

[service]
DISABLE_REGISTRATION = false
REQUIRE_SIGNIN_VIEW = false
REGISTER_EMAIL_CONFIRM = false
ENABLE_NOTIFY_MAIL = false
ALLOW_ONLY_EXTERNAL_REGISTRATION = false
ENABLE_CAPTCHA = false
DEFAULT_KEEP_EMAIL_PRIVATE = false
DEFAULT_ALLOW_CREATE_ORGANIZATION = true
DEFAULT_ENABLE_TIMETRACKING = true
NO_REPLY_ADDRESS = noreply.localhost

[lfs]
PATH = /data/git/lfs

[mailer]
ENABLED = false

[openid]
ENABLE_OPENID_SIGNIN = true
ENABLE_OPENID_SIGNUP = true

[cron.update_checker]
ENABLED = false

[repository.pull-request]
DEFAULT_MERGE_STYLE = merge

[repository.signing]
DEFAULT_TRUST_MODEL = committer

[oauth2]
JWT_SECRET = secret

clean app.ini with reverse proxy

APP_NAME = Gitea: Git with a cup of tea
RUN_MODE = prod
RUN_USER = git
WORK_PATH = /data/gitea

[repository]
ROOT = /data/git/repositories

[repository.local]
LOCAL_COPY_PATH = /data/gitea/tmp/local-repo

[repository.upload]
TEMP_PATH = /data/gitea/uploads

[server]
APP_DATA_PATH = /data/gitea
DOMAIN = git.example.org
SSH_DOMAIN = git.example.org
HTTP_PORT = 3000
ROOT_URL = https://git.example.org/
DISABLE_SSH = false
SSH_PORT = 222
SSH_LISTEN_PORT = 22
LFS_START_SERVER = true
LFS_JWT_SECRET = secret
OFFLINE_MODE = false

[database]
PATH = /data/gitea/gitea.db
DB_TYPE = sqlite3
HOST = localhost:3306
NAME = gitea
USER = root
PASSWD =
LOG_SQL = false
SCHEMA =
SSL_MODE = disable

[indexer]
ISSUE_INDEXER_PATH = /data/gitea/indexers/issues.bleve

[session]
PROVIDER_CONFIG = /data/gitea/sessions
PROVIDER = file

[picture]
AVATAR_UPLOAD_PATH = /data/gitea/avatars
REPOSITORY_AVATAR_UPLOAD_PATH = /data/gitea/repo-avatars

[attachment]
PATH = /data/gitea/attachments

[log]
MODE = console
LEVEL = info
ROOT_PATH = /data/gitea/log

[security]
INSTALL_LOCK = true
SECRET_KEY =
REVERSE_PROXY_LIMIT = 1
REVERSE_PROXY_TRUSTED_PROXIES = *
INTERNAL_TOKEN = token
PASSWORD_HASH_ALGO = pbkdf2

[service]
DISABLE_REGISTRATION = false
REQUIRE_SIGNIN_VIEW = false
REGISTER_EMAIL_CONFIRM = false
ENABLE_NOTIFY_MAIL = false
ALLOW_ONLY_EXTERNAL_REGISTRATION = false
ENABLE_CAPTCHA = false
DEFAULT_KEEP_EMAIL_PRIVATE = false
DEFAULT_ALLOW_CREATE_ORGANIZATION = true
DEFAULT_ENABLE_TIMETRACKING = true
NO_REPLY_ADDRESS = noreply.localhost

[lfs]
PATH = /data/git/lfs

[mailer]
ENABLED = false

[openid]
ENABLE_OPENID_SIGNIN = true
ENABLE_OPENID_SIGNUP = true

[cron.update_checker]
ENABLED = false

[repository.pull-request]
DEFAULT_MERGE_STYLE = merge

[repository.signing]
DEFAULT_TRUST_MODEL = committer

[oauth2]
JWT_SECRET = secret

I don’t notice anything wrong with app.ini or nginx config. Do you have any browser extensions installed? I have seen issues with others in past where weird behavior happened as a result of extension meddling with JS.

I’ve tested in Firefox, Chrome, Edge and on my phone’s firefox.
There are no extensions that would explain why specific parts are not working has they should…