Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

mtg: OIDC login with Google

Open
#139 0 comments 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 1 day

Nobody has claimed this yet.

Assessment

Difficulty
5/5
Estimated time
Over a week
Newbie friendliness
25/100
Issue type
Feature
Clarity
Clearly specified
Activity status
Active
Tech stack
rust, typescript

Research direction

Start by reading ADR-0002 and the glossaries at libs/galvyn-identity/GLOSSARY.md and services/mtg/GLOSSARY.md, then trace IdentitySetup and the auth handlers in services/mtg/src/http/handler_frontend/auth/handler.rs. The issue names config.rs, dev/common/env.common, deploy/mtg/env.example, the frontend login and signup pages, and the admin dashboard as implementation entry points. Run the specified HTTP harness tests and just ci; done means the acceptance criteria pass, including signup, returning login, locked accounts, collision handling, and no recovery or signup mail for external accounts.

Written by the indexing model from the issue text.

Description

Feature branch: mtg-oidc-login (starts with the glossary commit 32be03bd).

Goal

People can sign up for and log in to mtg with their Google account, as an alternative to Passkeys. This is the first OIDC login in the repo, built as the OIDC login method of libs/galvyn-identity that ADR-0002 already decided on.

Vocabulary follows libs/galvyn-identity/GLOSSARY.md and services/mtg/GLOSSARY.md (Local Account, External Account, External identity, OpenID provider). "Social login" is not a domain term; the UI may say "Continue with Google".

Decisions

  1. Google only, through generic OIDC. An OpenID provider is configured by issuer, client id, client secret and display name. GitHub and Discord are not OIDC and stay out (a separate decision). Apple comes later as its own step; the module should leave room for a signed (JWT) client secret and a form_post callback, but builds neither now.
  2. Local or external, never both, never switching (ADR-0002). A Local Account cannot add Google; an External Account cannot add a Passkey. No migration path in either direction.
  3. Google admits people on their first OIDC login. No Registration link needed.
  4. Username step. On a first OIDC login with an unknown External identity, the person picks a username. Until then a short-lived pending state in the session holds issuer, subject and email. Identity, External identity and Account are only created when the username is submitted; abandoning the step creates nothing.
  5. Email comes from the provider and is only accepted when email_verified is true; the person never types one. It is stored once and never synced on later logins (mtg has no email change for any Account).
  6. Email collision. If the verified email already belongs to an Account, the first OIDC login is refused with a hint to use Passkey login or recovery. Revealing that the address is in use is acceptable here: only the address's owner can present it verified.
  7. No recovery for External Accounts. Whoever controls the Google account can log in; if the Google account is gone, so is the mtg Account. The Identity module may support recovery for external Identities, mtg does not offer it.
  8. Lock works as for Local Accounts: OIDC login refused with locked, existing sessions fail on their next request.
  9. Deletion removes the Identity and External identity too. A later login with the same Google account goes through the username step and creates a new Account; the old public decks stay with the Tombstone.
  10. One button "Continue with Google" on both the login and the signup page. No username asked first: a known External identity logs in, an unknown one goes to the username step.
  11. Provider configuration via env vars, loaded with EnvLoader. Each provider is optional: without its env vars it is off and its button is hidden. An open endpoint lists the active providers (id + display name) for the frontend. No admin UI for providers.
  12. Admin dashboard shows whether an Account is local or external, and the provider, in both the Account list and the Account detail. Display only. The Admin log is unchanged.

Scope

libs/galvyn-identity: new oidc cargo feature
  • Models: External identity (issuer + subject, bound to exactly one external Identity), with a unique constraint on (issuer, subject). Cascade on Identity deletion.
  • Provider setup in IdentitySetup (issuer, client id, secret, display name, whether it admits on first login), discovery from the issuer.
  • Login ceremony: authorization code flow with PKCE, state and nonce, ID token validation (issuer, audience, expiry, nonce, signature via JWKS). Session keys stay owned by the module.
  • Outcome of a finished OIDC login: either the known Identity (logged in, last_login_at updated) or an unknown External identity held as the pending state, plus the verified email for the service.
  • An operation that binds the pending External identity to a fresh Identity, called by the service inside the transaction that creates its Account.
  • An Identity is local or external: Passkey enrollment refused for an external Identity, OIDC enrollment refused for a local one.
  • Updates to the crate docs (lib.rs), its GLOSSARY.md only if a new term emerges.
services/mtg
  • Enable the oidc feature, provider env vars in config.rs, dev/common/env.common and deploy/mtg/env.example.
  • Handlers: start OIDC login, callback, submit username for the pending state, list active providers. Username validation and the taken-username error as in signup.
  • Email collision check (decision 6) before the username step.
  • Fix recover_account (src/http/handler_frontend/auth/handler.rs): an External Account gets the same silent 200 and no mail. Today it would mail a Registration link that binds a Passkey to an external Identity.
  • Fix prepare_signup (same file): the "username taken but not yet registered" branch must check "has any login method", not "has a Passkey". Today a stranger could trigger an invite mail to an External Account's address by signing up with its username.
  • Admin dashboard schema: login method (local / external + provider) on Account list and detail.
  • Migrations via just make-migrations mtg.
  • HTTP tests (harness) with a fake OpenID provider: first login + username step, returning login, email collision, locked Account, recovery for an External Account is silent, signup with an External Account's username sends nothing.
frontend/mtg
  • "Continue with Google" on login and signup, shown only when the provider is active.
  • Username step page for the pending state.
  • Error states: email in use, Account locked, email not verified.
  • Admin dashboard: login method column / field.
  • i18n keys per CODING_STANDARDS.md; just gen-api mtg.

Out of scope

  • Apple, GitHub, Discord.
  • Switching an Account between local and external.
  • Recovery for External Accounts.
  • Email change for any Account.
  • OIDC for semmelei (the module makes it possible, nothing is wired).

Acceptance

  • A new person can sign up with Google, pick a username and land logged in; the Account is external and has the Google email.
  • The same person logs in again with one click, without a username.
  • A Google login whose verified email belongs to a Local Account is refused with the hint.
  • A locked External Account cannot log in, and its sessions die.
  • Recovery and signup never mail anything for an External Account.
  • Without Google env vars the button is gone and the service starts normally.
  • Admins see local / external (+ provider) per Account.
  • just ci and the gen-api drift check pass.
Dominant language
TypeScript
Stars
0
Forks
1
Avg merge
14h 36m
Merged PRs (30d)
24

Getting set up

This project ships no dev container, Dockerfile or contributing guide, so setting up is up to you: start from its README, and see our first-contribution guide for the general steps.

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from myOmikron/code

All issues in myOmikron/code

Similar issues

More TypeScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.