Как реализована аутентификация с поддержкой OpenID и OAuth 2.0
Что проверяют
Различаете ли вы авторизацию и аутентификацию: OAuth 2.0 выдаёт доступ к ресурсам, а личность пользователя подтверждает OpenID Connect, надстройка над ним. Старый OpenID 2.0 давно заброшен, сегодня под «OpenID» имеют в виду OIDC. Следом почти всегда спрашивают, как вы проверяете ID-токен и чем защищаетесь от перехвата кода.
Как отвечать
Опишите Authorization Code flow с PKCE, это стандарт и для серверных, и для публичных клиентов:
- редирект на провайдера:
oauth2.Config.AuthCodeURLсо случайнымstate,nonceи scopeopenid.stateи PKCE-верификатор (oauth2.GenerateVerifier,oauth2.S256ChallengeOption) храните в короткоживущей подписанной куке; - callback: сверяете
state, затемExchange(r.Context(), code, oauth2.VerifierOption(verifier)). Код меняется на токены на token endpoint сервера авторизации; - проверка ID-токена: пакет
github.com/coreos/go-oidc/v3/oidc.oidc.NewProviderчитает/.well-known/openid-configurationи ключи JWKS,Verifier(&oidc.Config{ClientID: ...}).Verifyпроверяет подпись,iss,audиexp.nonceсверяете сами; - своя сессия: из клеймов берёте
subиiss, связываете с пользователем в базе и выдаёте собственную сессию в кукеHttpOnly,Secure,SameSite=Lax. Токены провайдера в браузер не отдаёте; - обновление:
Config.TokenSource(ctx, token)сам обновит access-токен по refresh-токену, если провайдер его выдал. Часто для этого нужен scopeoffline_access.
Отдельно скажите, что Implicit flow и Password grant актуальная рекомендация по безопасности OAuth (RFC 9700) не одобряет, а oauth2.NoContext из старых примеров давно заменён обычным context.Context.
Где спотыкаются
Используют access-токен как доказательство входа. Он выпущен для API, а не для вашего приложения; личность подтверждает только проверенный ID-токен с правильным aud.
Ставят константный state или не проверяют его вовсе, забывают про PKCE. Это открывает CSRF на callback и перехват кода.
Декодируют JWT через base64 и верят клеймам без проверки подписи и издателя. Так пройдёт и поддельный токен, и выпущенный для чужого клиента.