decap-cms icon indicating copy to clipboard operation
decap-cms copied to clipboard

OAuth2 PKCE authentication with git-gateway-backend

Open pspizzo opened this issue 8 months ago • 9 comments

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 avatar Mar 27 '25 02:03 pspizzo

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?

https://github.com/decaporg/decap-cms/issues/7420

samo4 avatar Mar 28 '25 13:03 samo4

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.

pspizzo avatar Mar 28 '25 19:03 pspizzo

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.

samo4 avatar Mar 31 '25 08:03 samo4

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.

pspizzo avatar Apr 07 '25 02:04 pspizzo

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

samo4 avatar Apr 08 '25 14:04 samo4

Hello guys, can you please give more priority to this PR. Without it we have to rely on the deprecated Netlify Identity if we want to use Decap CMS with Netlify. @samo4 you mentioned you'd review it soon, but that was two months ago, so I'm guessing it might've slipped through the cracks. Could you please take a look when you get a chance? Would be great to get this moving forward again. Thanks!

yassine-safraoui avatar Jun 06 '25 19:06 yassine-safraoui

I am sorry if I read over something. But I am not really sure about the process here: Who is all able to review Pull request? Only PM Techhub Staff or are there others?

mnordhaus avatar Jun 07 '25 08:06 mnordhaus

Thanks for the approval. I think I need a maintainer to also approve the workflows, so they can run before the code is merged.

pspizzo avatar Jun 09 '25 21:06 pspizzo

we're testing it, will merge soon

samo4 avatar Jun 10 '25 12:06 samo4

There were merge conflicts with a recent commit to main, so I resolved the conflicts and repushed my branch. Please re-review.

pspizzo avatar Jun 17 '25 01:06 pspizzo

Hi, I wonder if there is a way that I could help to bring this forward to be merged?

mnordhaus avatar Jul 15 '25 08:07 mnordhaus

This has been sitting open for too long again, so new merge conflicts crept in. I merged the latest from main into my fork/branch, but I haven't had time to manually test it again. But unit tests all succeed locally.

pspizzo avatar Jul 15 '25 20:07 pspizzo

Now that the changes are approved and all checks have passed, what is the next step to get it merged?

pspizzo avatar Jul 18 '25 15:07 pspizzo

@samo4 I had to merge from main again, can you re-approve this request?

pspizzo avatar Jul 22 '25 15:07 pspizzo

Thanks @samo4 for approving the changes. Do you mind approving the workflows, so the automated builds can run?

pspizzo avatar Jul 22 '25 16:07 pspizzo

@pspizzo this is now released in v3.8.3. Please test. Would you be willing to contribute to the docs too?

Thanks for your first contribution!

martinjagodic avatar Jul 31 '25 08:07 martinjagodic

Just wanted to say great work with this one, thanks to this, SSO flows have now become possible with DecapBridge 🎉

loteoo avatar Oct 25 '25 17:10 loteoo

Just wanted to say great work with this one, thanks to this, SSO flows have now become possible with DecapBridge 🎉

I'm glad you found it useful!

pspizzo avatar Oct 26 '25 05:10 pspizzo