bitwarden / bitwarden/server

OpenID Connect response_mode handling - flawed discovery, missing validation

Open
#5,461 4 comments 3 reactions 0 assignees View on GitHub
bug good first issue
Dominant language
C#
Stars
20.1k
Forks
1.8k
Avg merge
4d 8h
Merged PRs (30d)
75

Description

### Steps To Reproduce

- You use an IdP that does not support (and actively rejects) `response_mode=form_post`
- You use bitwarden server's SSO functionality (OIDC) to login

### Expected Result

Bitwarden should have noticed from the discovery information that the IdP does not support `form_post` and consequently have set the respective query parameter value to `query`. Thus, the login would work.

### Actual Result

My strict IdP rejects users being redirected to it from bitwarden due to the unsupported parameter value.

### Screenshots or Videos

_No response_

### Additional Context

I would like to report two issues with the Bitwarden SSO implementation that recently surfaced on our end when we [upgraded our IdP](https://github.com/kanidm/kanidm/issues/3461#issuecomment-2683821694).

## Flawed discovery of `response_modes_supported`

- bitwarden does not consider the list of supported response modes advertised by the IdP
- the field is optional, however, the choice bitwarden makes (`form_post`) does not match the specified default if absent (`query` and `fragment`)
- it is also not possible to override this in the bitwarden configuration

Background:

> response_modes_supported
> OPTIONAL. JSON array containing a list of the OAuth 2.0 response_mode values that this OP supports, as specified in [OAuth 2.0 Multiple Response Type Encoding Practices](https://openid.net/specs/openid-connect-discovery-1_0.html#OAuth.Responses) [OAuth.Responses]. If omitted, the default for Dynamic OpenID Providers is ["query", "fragment"].

Source: https://openid.net/specs/openid-connect-discovery-1_0.html

## Missing validation of `form_post`

- **if** you choose to go down that `form_post` road, you should be validating how the response comes in
- currently you can swap the `response_mode` query parameter value to `query` (either manually as user in the browser or on-the-fly in a proxy) and bitwarden will continue processing although it requested a `form_post`

## Context

The first issue currently keeps us from upgrading our IdP because we either need to wait for them to relax validation on their end or we put a proxy-based hack in place.

In my view, you could just switch to `query` as a quick solution as this is what you have been accepting anyway so the situation does not get worse and it seems to be considered secure enough for the standard to choose it as default. You could allow administrators to change that to `form_post` in case their IdPs support that or you react to the discovery values.

I could provide more information, but I tried to reduce it to what someone implementing the OIDC authentication on your end would need to know to fix it. If you have OIDC-related questions I can recommend asking in the IdP-issue I linked as there is quite some domain expertise available over there.

### Build Version

bitwarden/nginx:2025.2.0, bitwarden/admin:2025.2.0, bitwarden/api:2025.2.0, bitwarden/icons:2025.2.0, bitwarden/web:2025.2.1, bitwarden/mssql:2025.2.0, bitwarden/attachments:2025.2.0, bitwarden/sso:2025.2.0, bitwarden/notifications:2025.2.0, bitwarden/events:2025.2.0, bitwarden/identity:2025.2.0

### Environment

Self-Hosted

### Environment Details

- OS: Arch Linux
- Environment: Docker

### Issue Tracking Info

- [x] I understand that work is tracked outside of Github. A PR will be linked to this issue should one be opened to address it, but Bitwarden doesn't use fields like "assigned", "milestone", or "project" to track progress.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.