Skip to content

OAuth2 PKCE authentication with git-gateway-backend #7439

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

Open
wants to merge 4 commits into
base: main
Choose a base branch
from

Conversation

pspizzo
Copy link

@pspizzo pspizzo commented Mar 27, 2025

Summary

With Netlify deprecating the Identity product, solutions need to be added to support additional authentication providers. This code adds support to the git-gateway backend for the OAuth2 PKCE authentication flow, without impacting any existing defaults.

Test plan

Test using the standard options with git-gateway and ensure that functionality is not affected.

Test with OAuth2 provider (I used Amazon Cognito). Example configuration that uses PKCE authentication (this is also documented in the decap-cms-backend-git-gateway README, for future use):

backend:
    name: git-gateway
    # Enables PKCE authentication with the git-gateway backend. After auth,
    # sends the access_token for all requests to the git-gateway host.
    auth_type: pkce
    # The base OAuth2 URL. Here is an obfuscated AWS Cognito example.
    base_url: https://your-cognito-instance.auth.us-east-1.amazoncognito.com
    # If you need to customize the authorize or token endpoints for PKCE, do that here
    #auth_endpoint: oauth2/authorize
    #auth_token_endpoint: oauth2/token
    # The OAuth2 client ID
    app_id: your-oauth2-client-id
    # The base URL of your custom git-gateway. Note that the last part of the path
    # should be "bitbucket", "gitlab", or "github", so the implementation can automatically
    # determine which backend API to use when making requests.
    gateway_url: https://your.gitgateway.host/git-gateway/bitbucket/
    # Optional: defaults to "master"
    branch: main

Checklist

bunny

@pspizzo pspizzo requested a review from a team as a code owner March 27, 2025 02:10
@samo4
Copy link
Collaborator

samo4 commented Mar 28, 2025

I have a couple of discussion points about this PR. These are not necessarily directly related to your PR, but to general decap architecture and it's limitations. Also to the way the oauth vendors mangle up the standard.

So first this is that there's an almost exact copy of your PKCEAuthenticationPage.js already in the repo. It's also claimining to be generic but in it's not in practice.

Basicly we need to decide if we'll have one module to handle all the providers, or a module for each. A combination of the two aproaches will be a mess. I tried Azure B2C with your code and after some tweaking I came to the login page. However the completeAuth part seems to be totally different to what Cognito does.

Perhaps we should start with a list of providers that we want to support?

#7420

@pspizzo
Copy link
Author

pspizzo commented Mar 28, 2025

So first this is that there's an almost exact copy of your PKCEAuthenticationPage.js already in the repo. It's also claimining to be generic but in it's not in practice.

True, I saw the existing file and re-used it. There are some changes added to mangle the claims into a format acceptable by git-gateway, but some deduplication could be done with the code between those two classes, if you prefer. I just didn't want to add a dependency on an undocumented backend file.

Basicly we need to decide if we'll have one module to handle all the providers, or a module for each. A combination of the two aproaches will be a mess. I tried Azure B2C with your code and after some tweaking I came to the login page. However the completeAuth part seems to be totally different to what Cognito does.

In theory, the actual authentication mechanism (PKCE flow) should be the same, right? If so, perhaps we just need a way to normalize the claims from each provider, hopefully with overrideable autodetection. Personally, as a user of the Decap app, I'd expect PKCE to work regardless of provider, and wouldn't want to be limited to a smaller set of providers when any OAuth2 should work, as long as the necessary data is somewhere in the claims.

If you like, I can move the PKCE auth UI and associated claim-normalization into a separate module, and use that in both backends.

@samo4
Copy link
Collaborator

samo4 commented Mar 31, 2025

In theory, the actual authentication mechanism (PKCE flow) should be the same, right?

In theory, yes. It's just that the vendors didn't get the message. Here are my notes for Azure B2C (the idea is to take these notes and add options to PkceAuthenticator):

  • the URL's are not build the same way as Cognito. Authenticate url looks like this: /<policy>/oauth2/v2.0/authorize, completeAuth url looks like this: /<policy>/oauth2/v2.0/token
  • authenticate: nonce is not in state, but as a separete parameter (perhaps we can assume that vendors will ignore extra params?)
  • authenticate: state includes: meta: { interactionType: 'redirect' }
  • completeAuth: I think that nonce should be completely ignored

If you like, I can move the PKCE auth UI and associated claim-normalization into a separate module, and use that in both backends.

That would be great. The idea is not so much that you need to support all of them, just that there's enough flexibility in the implementation so that others can be added without too much work and too much duplication. So split what's really generic to common module. Don't be afraid to rip out the old stuff.

@pspizzo
Copy link
Author

pspizzo commented Apr 7, 2025

I updated the PR with some refactoring and some improvements:

  • I moved the PKCE and Netlify auth pages to a new UI library, so identical auth pages do not need to be created across backends. These were moved from the git-gateway and aws-cognito-github-proxy backends.
  • I added a new config section, named auth, which can be used to configure more fine-tuned options to the authentication providers. The original values from backend (ex: "base_url") are still recognized, for backwards-compatibility, but any explicit options provided in auth will be preferred
  • I added options for converting claim data to the fields expected by git-gateway. The most important one is email -- if your provider isn't returning an explicit email claim in the access or ID token, but it is available in a different claim, add auth.email_claim in your config to the name of the claim.
  • I added basic OpenID Connect endpoint autodiscovery to the pkce-oauth library, turned off by default. Add auth.use_oidc: true in your config, and assuming your auth.base_url (or backend.base_url) is a valid OIDC issuer with a .well-known/openid-configuration URL, the code will figure out the auth and token endpoints for you

I didn't touch any of the nonce/state logic, since I don't have an Azure B2C provider. If I have time this week, I can try firing up a basic test Azure App Registration and see if it works, but I don't know if that is significantly different from B2C.

One comment about Azure and OAuth that I ran into a few weeks ago for something completely unrelated: by default, Azure App Registrations use OAuth v1, which has very different claims from OAuth v2. I wouldn't be surprised if B2C had the same default. To switch over to v2 for App Registrations, you need to edit the manifest manually, find the requestedAccessTokenVersion setting in the manifest, and set it to the number 2 (by default, it's null, and MS uses v1 as the default). Save it and wait like 15 minutes for it to take effect.

Do you know if your B2C testing was on v1 or v2? If you aren't sure, trying decoding the JWT, it should have a version or similar claim with 1 or 2.

@samo4
Copy link
Collaborator

samo4 commented Apr 8, 2025

Sorry, I'm busy, will take a look during the weekend or sooner.

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