Skip to content

Conversation

@shaun-nx
Copy link
Contributor

@shaun-nx shaun-nx commented Nov 27, 2025

Proposed changes

This change adds a new GoLang API type to apis/v1alpha1 for the AuthenticationFilter
This change only adds the types required for Basic Auth to work, and does not include types specific to JWT Auth. These will be added in future work.

Closes #4309

Example manifest for basic auth

apiVersion: gateway.nginx.org/v1alpha1
kind: AuthenticationFilter
metadata:
  name: basic-auth
spec:
  type: Basic
  basic:
    secretRef:
      name: basic-auth-users
    realm: "Restricted"
    onFailure:
      statusCode: 401
      scheme: Basic

Example output from kubectl describe authenticationfilters.gateway.nginx.org basic-auth

Name:         basic-auth
Namespace:    default
Labels:       <none>
Annotations:  <none>
API Version:  gateway.nginx.org/v1alpha1
Kind:         AuthenticationFilter
Metadata:
  Creation Timestamp:  2025-11-27T10:49:42Z
  Generation:          1
  Resource Version:    58448
  UID:                 b0f0a18a-ba43-453c-b315-dcecf39ad06f
Spec:
  Basic:
    On Failure:
      Body Policy:  Unauthorized
      Scheme:       Basic
      Status Code:  401
    Realm:          Restricted
    Secret Ref:
      Name:  basic-auth-users
  Type:      Basic
Events:      <none>

Validation

Performed manual checks on x-Kubernetes-Validations for CRD:

  1. Rule: for type=Basic, spec.basic must be set

File used:

apiVersion: gateway.nginx.org/v1alpha1
kind: AuthenticationFilter
metadata:
  name: basic-auth
spec:
  type: Basic
  # spec.basic is missing

Result:

The AuthenticationFilter "basic-auth" is invalid: 
* spec.basic: Required value
* <nil>: Invalid value: null: some validation rules were not checked because the object was invalid; correct the existing errors to complete validation
  1. Rule: when spec.basic is set, type must be 'Basic'

Files used:

  1. where type is not defined
  2. where type is set to Blah
apiVersion: gateway.nginx.org/v1alpha1
kind: AuthenticationFilter
metadata:
  name: basic-auth-empty-type
spec:
  # type field is missing
  basic:
    secretRef:
      name: basic-auth-users
    realm: "Restricted"    
    onFailure:                
      statusCode: 401
      scheme: Basic
---
apiVersion: gateway.nginx.org/v1alpha1
kind: AuthenticationFilter
metadata:
  name: basic-auth-empty-blah
spec:
  type: Blah  # type field is invalid
  basic:
    secretRef:
      name: basic-auth-users
    realm: "Restricted"    
    onFailure:                
      statusCode: 401
      scheme: Basic

Results:

Error from server (Invalid): error when creating "STDIN": AuthenticationFilter.gateway.nginx.org "basic-auth-empty-type" is invalid: [spec.type: Required value, <nil>: Invalid value: null: some validation rules were not checked because the object was invalid; correct the existing errors to complete validation]
Error from server (Invalid): error when creating "STDIN": AuthenticationFilter.gateway.nginx.org "basic-auth-empty-blah" is invalid: [spec.type: Unsupported value: "Blah": supported values: "Basic", <nil>: Invalid value: null: some validation rules were not checked because the object was invalid; correct the existing errors to complete validation]

Checklist

Before creating a PR, run through this checklist and mark each as complete.

  • I have read the CONTRIBUTING doc
  • I have added tests that prove my fix is effective or that my feature works
  • I have checked that all unit tests pass after adding my changes
  • I have updated necessary documentation
  • I have rebased my branch onto main
  • I will ensure my PR is targeting the main branch and pulling from my branch from my own fork

Release notes

If this PR introduces a change that affects users and needs to be mentioned in the release notes,
please add a brief note that summarizes the change.

NONE

@shaun-nx shaun-nx requested a review from a team as a code owner November 27, 2025 11:23
@github-actions github-actions bot added the enhancement New feature or request label Nov 27, 2025
@codecov
Copy link

codecov bot commented Nov 27, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
⚠️ Please upload report for BASE (feat/authentication-filter-basic-auth@82a86f4). Learn more about missing BASE report.

Additional details and impacted files
@@                           Coverage Diff                            @@
##             feat/authentication-filter-basic-auth    #4349   +/-   ##
========================================================================
  Coverage                                         ?   86.11%           
========================================================================
  Files                                            ?      132           
  Lines                                            ?    14343           
  Branches                                         ?       35           
========================================================================
  Hits                                             ?    12351           
  Misses                                           ?     1787           
  Partials                                         ?      205           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@tataruty
Copy link
Contributor

the target should be feat/authentication-filter-basic-auth i guess

@shaun-nx shaun-nx changed the base branch from main to feat/authentication-filter-basic-auth November 27, 2025 11:41
@shaun-nx
Copy link
Contributor Author

shaun-nx commented Nov 27, 2025

The linter seemed to have problems with the comments the AuthenticationFilterSpec and BasicAuth structs: a127e6b
This does affect the description given for secret ref. See here: https://github.com/nginx/nginx-gateway-fabric/pull/4349/commits/da972012a91784412d617785b81d79210db1fb10#diff-085e561f7a49fee[…]9fc1703ae43dbL97-R93
I'm not sure if there is a way around this. What do you all think?

@sjberman
Copy link
Collaborator

The linter seemed to have problems with the comments the AuthenticationFilterSpec and BasicAuth structs

@shaun-nx I think I wrote about this on another PR, but the linter (fieldalignment) does not have a problem with comments. The linter automatically reorganizes fields within a struct to optimize it for the compiler. There is a bug that causes comments to be removed when it does this, so you have to manually add the comments back in.

@shaun-nx
Copy link
Contributor Author

The linter seemed to have problems with the comments the AuthenticationFilterSpec and BasicAuth structs

@shaun-nx I think I wrote about this on another PR, but the linter (fieldalignment) does not have a problem with comments. The linter automatically reorganizes fields within a struct to optimize it for the compiler. There is a bug that causes comments to be removed when it does this, so you have to manually add the comments back in.

Thanks Saylor. We managed to fix it too. @tataruty pointed out the same thing. Will probably be one of those things that I need to see a few times before I remember haha.

@shaun-nx shaun-nx requested a review from tataruty November 28, 2025 09:26

const (
AuthSchemeBasic AuthScheme = "Basic"
AuthSchemeBearer AuthScheme = "Bearer"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we mention in comment that bearer is for JWT auth?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch! Since we're just implementing Basic Auth now, I'll remove Bearer as an option.

@tataruty tataruty mentioned this pull request Dec 1, 2025
6 tasks
@shaun-nx shaun-nx requested a review from tataruty December 1, 2025 13:55
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Following a response to a comment in my RL doc, we typically have our fields as pointers. What makes a field optional is the // +optional tag for kubebuilder not if it is a pointer or not.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From what I remember, we only use pointers on our Optional fields.
Are you saying all fields should be pointers?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm, as i checked the other apis we have, it seems like i was mistaken, yea we only use pointers on our optional fields, so you can disregard my comment

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You have a lot of fields defined here that should be optional but aren't.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Scratch my last comment, I misread. However, BasicAuth in the top level spec should be optional.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for calling that one out. I had planned on having it as a required field and making it optional only after JWT auth was added as well, but that might break the API. I'll update that to be optional

Copy link
Collaborator

@sjberman sjberman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See #4266 for an example of API structure and other things that should be implemented as part of this.

//
// +optional
// +kubebuilder:default=401
// +kubebuilder:validation:XValidation:message="statusCode must be 401 or 403",rule="self in [401, 403]"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You don't need CEL for this, you can use an enum.

// +kubebuilder:validation:Enum=401;403

Copy link
Contributor Author

@shaun-nx shaun-nx Dec 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, that's a good point. I'll change that.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please ensure that all fields have comments associated with them that describe what the field is.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When through them all. From what I can see they should all have descriptive comments.
Some of the type fields were missing the same comment separation as well so I added them were I saw they were missing here

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

constants should have comments as well

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be updated now.

Comment on lines 89 to 90
// AuthFailureBodyPolicy controls the failure response body behavior.
// +kubebuilder:validation:Enum=Unauthorized;Forbidden;Empty
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// AuthFailureBodyPolicy controls the failure response body behavior.
// +kubebuilder:validation:Enum=Unauthorized;Forbidden;Empty
// AuthFailureBodyPolicy controls the failure response body behavior.
//
// +kubebuilder:validation:Enum=Unauthorized;Forbidden;Empty

We like the separation between descriptive and functional comments. Be sure to apply to all other fields in the same way.

Comment on lines 99 to 101
// AuthFailureResponse customizes 401/403 failures.
//

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

comment malformed

Comment on lines +23 to +26
// Status defines the state of the AuthenticationFilter, following the same
// pattern as SnippetsFilter: per-controller conditions with an Accepted condition.
//
// +optional
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// Status defines the state of the AuthenticationFilter, following the same
// pattern as SnippetsFilter: per-controller conditions with an Accepted condition.
//
// +optional
// Status defines the state of the AuthenticationFilter.

No need to reference another filter in here, can just keep this isolated. It also shouldn't be marked as optional.

}

// AuthenticationFilterSpec defines the desired configuration.
// +kubebuilder:validation:XValidation:message="for type=Basic, spec.basic must be set",rule="self.type == 'Basic' ? self.basic != null : true"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since Basic is optional, no need for this validation.

// Basic configures HTTP Basic Authentication.
//
// +optional
Basic *BasicAuth `json:"basic"`
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Basic *BasicAuth `json:"basic"`
Basic *BasicAuth `json:"basic,omitempty"`

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unless this isn't needed due to being a nested struct?


// BasicAuth configures HTTP Basic Authentication.
type BasicAuth struct {
// OnFailure customizes the 401 response for failed authentication.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// OnFailure customizes the 401 response for failed authentication.
// OnFailure customizes the response for failed authentication.

type AuthScheme string

const (
AuthSchemeBasic AuthScheme = "Basic" // For Basic Auth.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment should be above the field and follow the usual format.

AuthFailureBodyPolicyEmpty AuthFailureBodyPolicy = "Empty"
)

// AuthFailureResponse customizes 401/403 failures.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// AuthFailureResponse customizes 401/403 failures.
// AuthFailureResponse customizes auth response failures.

Comment on lines +113 to +114
// Allowed: 401, 403.
// Default: 401.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need a more descriptive comment on what the StatusCode field actually is.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the 401 default provided by nginx? If not, then we'll need to set the default with the kubebuilder tag in the spec.

// Configures WWW-Authenticate header in error page location.
//
// +optional
// +kubebuilder:default=Basic
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we infer from the filter type, then we don't need to set a default in here. Otherwise, it's impossible to omit.

// Default: Unauthorized.
//
// +optional
// +kubebuilder:default=Unauthorized
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this an nginx default or our own default?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

Status: 🆕 New

Development

Successfully merging this pull request may close these issues.

Generate base CRDs for AuthenticationFilter

5 participants