Skip to content

Add OIDC implementation with authentication and configuration support#1663

Closed
JatinVasman wants to merge 4 commits intoKruptein:devfrom
JatinVasman:oidc-implementation
Closed

Add OIDC implementation with authentication and configuration support#1663
JatinVasman wants to merge 4 commits intoKruptein:devfrom
JatinVasman:oidc-implementation

Conversation

@JatinVasman
Copy link
Copy Markdown

Implements OpenID Connect authentication allowing users to login with external providers.
Features:
OIDC authentication flow with multiple provider support
Account linking via email for existing users
Configurable via environment variables
Added login UI with provider buttons
Changes:
Backend: OIDC auth module, API endpoints, configuration
Frontend: Updated login page with OIDC buttons and callback handling
Config: Environment template and Docker compose setup
No breaking changes - OIDC is optional and works alongside existing auth.

@Kruptein
Copy link
Copy Markdown
Owner

I don't have the time yet for a full review, but just wanted to say that there is nothing wrong with using the http:// string, the sonarcloud analysis is just that an analysis, if there are elements it brings up that are not actually a problem I can allow them :p

It's not the intention to obfuscate the code with complexer logic just to avoid using "http" ;)

Copy link
Copy Markdown
Owner

@Kruptein Kruptein left a comment

Choose a reason for hiding this comment

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

I still need to review the actual oidc code, but there is a lot of noise from other changes that are not related.

I'm assuming something went wrong with the base branch you come from, as a bunch of things that were recently changed in PA are reverted in this PR.

Additionally there are some infra things for docker and env variables, that I would rather keep out of this PR.

"login": {
"register": "Register",
"login": "Login",
"or": "OR",
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

This already exists as common.ok


import { router } from ".";

// Admin
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Why are these removed

Comment thread docker-compose.yml
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

This is not relevant to the PR

Comment thread server/pyproject.toml
"rtoml==0.12.0",
"typing-extensions==4.15.0",
"watchdog==6.0.0",
"requests>=2.32.5",
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

This is not sorted, but also seemingly not actually used?
We have aiohttp for network requests anyway.

Comment thread server/src/auth/core.py
Comment on lines +36 to +48
user: Union[User, None] = User.by_name(identity) if identity else None
if user is None:
return False

if permission == "lobby.read":
if user.role != Constants.role.DM:
return user.can_play_game(context["room"])
return True
elif permission == "dm":
return user.role == Constants.role.DM
elif permission == "token.read":
return user.role == Constants.role.DM
return False
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

This seems to use some custom permission logic you have for your personal server I'm assuming.

These permissions don't exist, so just reset this to the original behaviour please.

Comment thread server/src/routes.py

if username_pass_should_be_disabled:
data = data.replace(b'name="PA-username-pass" content="true"', b'name="PA-username-pass" content="false"')
elif not config.general.username_password_enabled and not oidc_fully_configured:
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

This is now checked twice, both in the condition on line 39 and here

Comment thread server/src/routes.py
pass # Meta tag stays as content="true"

# MAIL CONFIGURATION
if config.mail is None or not config.mail.enabled or not config.mail.host or not config.mail.port or not config.mail.default_from_address:
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

host, port and the default email cannot be empty if config.mail exists so checking them is unnecessary

Comment thread server/src/routes.py
Comment on lines +32 to +34
config.oidc.client_id and
config.oidc.client_secret and
bool(config.oidc.domain or config.oidc.authorize_url) # Either domain for discovery OR direct URLs
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

These should just become mandatory in the config. If you specify an oidc config, it should contain all the data required.

For the domain vs authorize_url we probably should ideally check that in a sort of post-validation step in the config manager itself, but I'm ok with keeping it here for now

Comment thread server/src/routes.py
Comment on lines +82 to +91

async def root(request, admin_api=False):
template = "admin-index.html" if admin_api else "index.html"
with open(FILE_DIR / "templates" / template, "rb") as f:
data = __replace_config_data(f.read())
return web.Response(body=data, content_type="text/html")


async def root_dev(request):
port = 8080
async def root_dev(request, admin_api=False):
port = 8081 if admin_api else 8080
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Revert these

Comment thread server/src/routes.py
Comment on lines +133 to +152
# ADMIN ROUTES

api_app.router.add_post(f"{subpath}/notifications", notifications.create)
api_app.router.add_get(f"{subpath}/notifications", notifications.collect)
api_app.router.add_delete(f"{subpath}/notifications/{{uuid}}", notifications.delete)
api_app.router.add_get(f"{subpath}/users", admin_users.collect)
api_app.router.add_post(f"{subpath}/users/reset", admin_users.reset)
api_app.router.add_post(f"{subpath}/users/remove", admin_users.remove)
api_app.router.add_get(f"{subpath}/campaigns", campaigns.collect)

admin_app.router.add_static(f"{subpath}/static", STATIC_DIR)
admin_app.add_subapp("/api/", api_app)

TAIL_REGEX = "/{tail:(?!api).*}"
if "dev" in sys.argv:
main_app.router.add_route("*", TAIL_REGEX, root_dev)
admin_app.router.add_route("*", TAIL_REGEX, partial(root_dev, admin_api=True))
else:
main_app.router.add_route("*", TAIL_REGEX, root)
admin_app.router.add_route("*", TAIL_REGEX, partial(root, admin_api=True))
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Revert these

@Kruptein
Copy link
Copy Markdown
Owner

Hey @JatinVasman just checking in to see if you're still up for working on this :)

I hope I didn't scare you :D I'm still interested in expanding the login options.

@Kruptein
Copy link
Copy Markdown
Owner

I'm going to close this in favour of #1701, which is based on your changes (and credits you in the changelog).

@Kruptein Kruptein closed this Nov 14, 2025
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.

2 participants