Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support Upstream OIDC Providers without a ClientSecret #3194

Open
2 tasks done
cameronbrunner opened this issue Nov 15, 2023 · 2 comments
Open
2 tasks done

Support Upstream OIDC Providers without a ClientSecret #3194

cameronbrunner opened this issue Nov 15, 2023 · 2 comments

Comments

@cameronbrunner
Copy link

cameronbrunner commented Nov 15, 2023

Preflight Checklist

  • I agree to follow the Code of Conduct that this project adheres to.
  • I have searched the issue tracker for an issue that matches the one I want to file, without success.

Problem Description

When using the OIDC connector Dex should support a secure method for distributing a common configuration file that could be used by multiple instances of a given application. Presently this is not possible as the OIDC connector requires both a ClientID and ClientSecret leading to either the distribution of the ClientSecret to all application instances or a unique ClientID for application instances. The former is insecure and the later is unfeasible with significantly large numbers of application instances.

Proposed Solution

OIDC classifies client applications into two categories, Confidential and Public. Dex presently behaves only as a Confidential application and thus requires a ClientID and ClientSecret. I propose that support for Public be added as an option to the OIDC connector.

I believe all that is required is:

  1. Add a new configuration option to enable Public mode for connectors.
  2. When public mode is enabled allow for an empty ClientSecret
  3. When public mode is enabled add a S256 Challenge option when generating the OIDC AuthCodeURL.
  4. Use the appropriate verifier when running 'Exchange' later on in the flow.

The majority fo the actual work is handled in the downstream golang oidc code and was added in April of this year:

golang/oauth2#603
golang/go#59835

Some sample code.

Add something like this to the LoginURL function (

func (c *oidcConnector) LoginURL(s connector.Scopes, callbackURL, state string) (string, error) {
)

    if c.Public {
        verifier := oauth2.GenerateVerifier()
        opts = append(opts, oauth2.S256ChallengeOption(verifier))
        // Add state and verifier to a connector level cache with a short expiration.  Referenced in Exchange later.
       }

And this to HandleCallback (https://github.com/dexidp/dex/blob/e41a28bf27225ab503eb9feef4feedd03bb4ac71/connector/oidc/oidc.go#L291C18-L291C18)

    state := q.Get("state")
    // Look up state in cache
    var tok *oauth2.Token
    var err error
    if cachedVerifier == nil {
        tok, err = c.oauth2Config.Exchange(ctx, code)
    } else {
        tok, err = c.oauth2Config.Exchange(ctx, code, oauth2.VerifierOption(cachedVerifier))
    }

Alternatives Considered

  1. Distributed a shared secret to multiple applications which would be too insecure.
  2. Creating secrets for each application instance which could be infeasible with large numbers of dynamic applications.

Additional Information

Discussion on Confidential and Public OIDC applications - https://auth0.com/docs/get-started/applications/confidential-and-public-applications

@cameronbrunner
Copy link
Author

FWIW - I have a separate golang application where I have added a variant of the suggested improvement and have verified its use with Okta as an upstream OIDC provider.

@cameronbrunner cameronbrunner changed the title Support Upstream OIDC Servers without a ClientSecret Support Upstream OIDC Providers without a ClientSecret Nov 15, 2023
@cameronbrunner
Copy link
Author

Another implementation offered here #3188

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

No branches or pull requests

1 participant