Skip to content

Integration with OIDC is misbehaving #34358

Open
@flixman

Description

@flixman

Description

I am using gitea behind authelia, for which I have already set up an OIDC client. The client is set up this way:

gitea admin auth add-oauth --name authelia --provider openidConnect --key gitea --secret {{ authelia.apps.gitea_password }} --auto-discover-url "https://auth.{{ domain }}/.well-known/openid-configuration" --scopes 'openid email profile groups' --admin-group gitea_admin

For unprivileged users, I get the consent form, login, logout, log back in and... everything works.

For admin users, that is not the case:

  • The first time I log in, I get the consent form, then I confirm the username and email and all works
  • For any other login, I get a 500 error with this message on the logs:
2025/05/04 09:03:29 ...rs/web/auth/oauth.go:351:handleOAuth2SignIn() [E] UpdateUser: can not delete the last admin user [uid: 1]

Should I create a static (local) admin user with a random password (so that there is one admin user left always), then using the OIDC user works... but, although it is still in the admin group, it gets created as an unprivileged user. Authelia is still sending the group information:

time="2025-05-04T07:12:48Z" level=debug msg="Check authorization of subject username=appadmin groups=harbor_admin,gitea_admin ip=10.42.0.1 and object https://gitea.test.local/user/oauth2/authelia/callback?code=authelia_ac_xuKzjjvjSDN5jChi3nH1onld9A8u1c6JiP6Qa8p82Uc.9qzzwoc214JC4BZ_pXBIozwfXU24dhsaIwAr7N_XQuE&iss=https%3A%2F%2Fauth.test.local&scope=openid+email+profile+groups&state=72f8a6cc-8a6d-4d5e-99fe-f6cdde3820c1 (method GET)."
time="2025-05-04T07:12:48Z" level=debug msg="Access Request with id '11cf7b62-12e9-4e6e-aab7-a9632d41e672' on client with id 'gitea' is being processed" method=POST path=/api/oidc/token remote_ip=10.42.0.1
time="2025-05-04T07:12:48Z" level=debug msg="Access Request with id '11cf7b62-12e9-4e6e-aab7-a9632d41e672' on client with id 'gitea' has successfully been processed" method=POST path=/api/oidc/token remote_ip=10.42.0.1

if I then list the users in gitea, I get the following:

gitea admin user list
ID   Username Email               IsActive IsAdmin 2FA
1    appadmin appadmin@test.local true     **false**   false
2    appuser  appuser@test.local  true     false   false
3    admin    admin@local         true     true    false

so... seems that the groups information is not properly read by gitea on any logins after the first?

Gitea Version

1.23.7

Can you reproduce the bug on the Gitea demo site?

No

Log Gist

No response

Screenshots

No response

Git Version

the one coming with the container docker.io/gitea/gitea:latest

Operating System

No response

How are you running Gitea?

through podman, from the image docker.io/gitea/gitea:latest

Database

PostgreSQL

Activity

0dragosh

0dragosh commented on May 5, 2025

@0dragosh

I have the exact same issue.

techknowlogick

techknowlogick commented on May 5, 2025

@techknowlogick
Member

@0dragosh are you able to confirm with the 1.24-RC0 that was just released?

flixman

flixman commented on May 5, 2025

@flixman
Author

@techknowlogick I have just given it a try, and I am getting the same error with 1.24.0-rc0-rootless. This is the log in Gitea:

2025/05/05 21:10:20 HTTPRequest [I] router: completed GET /user/oauth2/authelia for 10.42.0.1:0, 307 Temporary Redirect in 1.6ms @ auth/oauth.go:37(auth.SignInOAuth)
2025/05/05 21:10:20 routers/web/auth/oauth.go:353:handleOAuth2SignIn() [E] UpdateUser: can not delete the last admin user [uid: 1]
2025/05/05 21:10:20 HTTPRequest [I] router: completed GET /user/oauth2/authelia/callback?code=authelia_ac_rEwIj1uSvjZqwld5OXjVbhrJxucGbMmeGB_gOJTCU_c.Zed6GXiXuBERtf0P--4pYUXJNHF_ub57YXwpo2G-9WA&iss=https%3A%2F%2Fauth.test.local&scope=openid+email+profile+groups&state=cccfc51d-e073-4f3c-99da-d3ab1f6d071f for 10.42.0.1:0, 500 Internal Server Error in 231.7ms @ auth/oauth.go:76(auth.SignInOAuthCallback)
flixman

flixman commented on May 12, 2025

@flixman
Author

I done some more tests, today and indeed seems that the group information is not passed properly. I have made sure that in the token provided by authelia there is a "groups" claim, in this case, without membership to the gitea_admin group:

Image

I have also added the flag --group-claim-name groups to the add-oauth call, and now I am starting to log in (first user after a database wipe) with an unprivileged user... and it shows as if it was an admin :-O!

Image
Just for the record, there is no other user in the database:

Image
So.... what's wrong?

flixman

flixman commented on May 17, 2025

@flixman
Author

@techknowlogick @0dragosh with version 1.23.8 the problem is that the first user is set as admin no matter what. There seems to be a (possibly outdated) code block that returns the error we see although no admin is deleted anywhere. I know too little about the architecture to happily remove that part :-/. However, the solution seems to be to add a dummy admin as the first user, and then everything seems to be ok (for now)

	if opts.IsAdmin.Has() {
		if !opts.IsAdmin.Value() && user_model.IsLastAdminUser(ctx, u) {
			return models.ErrDeleteLastAdminUser{UID: u.ID}
		}

		u.IsAdmin = opts.IsAdmin.Value()

		cols = append(cols, "is_admin")
	}
0dragosh

0dragosh commented on May 17, 2025

@0dragosh

Sorry for not replying sooner but I am running Forgejo and this seems to be a shared code path. My bad.

techknowlogick

techknowlogick commented on May 17, 2025

@techknowlogick
Member

Yes, at least one admin user is required.

lunny

lunny commented on May 17, 2025

@lunny
Member

@techknowlogick @0dragosh with version 1.23.8 the problem is that the first user is set as admin no matter what. There seems to be a (possibly outdated) code block that returns the error we see although no admin is deleted anywhere. I know too little about the architecture to happily remove that part :-/. However, the solution seems to be to add a dummy admin as the first user, and then everything seems to be ok (for now)

if opts.IsAdmin.Has() {
if !opts.IsAdmin.Value() && user_model.IsLastAdminUser(ctx, u) {
return models.ErrDeleteLastAdminUser{UID: u.ID}
}

  u.IsAdmin = opts.IsAdmin.Value()

  cols = append(cols, "is_admin")

}

Who can login with that dummy admin account? I don't think it can be simply removed.

flixman

flixman commented on May 18, 2025

@flixman
Author

@lunny Nobody is expected to use that dummy account. Maybe I am looking at this the wrong way, but what I am aiming towards to is: I want to have all the identities provided externally, in this case by Authelia. With my current configuration, when I get to gitea -> sign in, I just get a button to use authelia login (I'd like this to happen without having to click the button, but I think is not possible?) and then have the information about users, groups, etc., sent over by Authelia. All this works, as long as the first user in gitea is an admin.

I guess this should be stated as a requirement somewhere? Having an app relying only on externally provided ids is not that a corner case nowadays.

added
type/enhancementAn improvement of existing functionality
and removed on May 18, 2025
lunny

lunny commented on May 18, 2025

@lunny
Member

If nobody is admin, how could you maintain the site? I think the best way is keeping at least one user as admin in authelia side?

flixman

flixman commented on May 18, 2025

@flixman
Author

@lunny because, in the oauth2 client, I am setting that the users belonging to gitea_admin group are admins. There are admins, it's only that they are not local.

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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @lunny@techknowlogick@flixman@0dragosh@kemzeb

        Issue actions

          Integration with OIDC is misbehaving · Issue #34358 · go-gitea/gitea