refactor: reuse generic OIDC provider logic in Apple provider

Address review feedback:
- Wire OIDCOptions through NewOIDCProvider instead of constructing
  OIDCProvider manually
- Default AuthRequestResponseMode to form_post instead of overriding
  GetLoginURL
- Drop the ValidateSession override in favour of the generic OIDC one
- Use options.AppleProvider constant in client secret validation
- Regenerate alpha config docs (appleConfig, authStyle)
- Fix CHANGELOG entry to reference #3293

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

Signed-off-by: LYJW131 <lyjw2007@gmail.com>
This commit is contained in:
LYJW131 2026-07-19 13:20:15 +08:00
parent 33252dd11c
commit 15dfd6e617
3 changed files with 28 additions and 44 deletions

View File

@ -312,6 +312,19 @@ They may change between releases without notice.
| `metricsServer` | _[Server](#server)_ | MetricsServer is used to configure the HTTP(S) server for metrics.<br/>You may choose to run both HTTP and HTTPS servers simultaneously.<br/>This can be done by setting the BindAddress and the SecureBindAddress simultaneously.<br/>To use the secure server you must configure a TLS certificate and key. |
| `providers` | _[Providers](#providers)_ | Providers is used to configure your provider. **Multiple-providers is not<br/>yet working.** [This feature is tracked in<br/>#925](https://github.com/oauth2-proxy/oauth2-proxy/issues/926) |
### AppleOptions
(**Appears on:** [Provider](#provider))
| Field | Type | Description |
| ----- | ---- | ----------- |
| `teamID` | _string_ | TeamID is the 10-character Apple Developer Team ID |
| `keyID` | _string_ | KeyID is the 10-character identifier for the private key |
| `privateKey` | _string_ | PrivateKey is the PEM-encoded ES256 private key content (from .p8 file) |
| `privateKeyFile` | _string_ | PrivateKeyFile is the path to the .p8 private key file |
### AzureOptions
(**Appears on:** [Provider](#provider))
@ -552,6 +565,7 @@ character.
| `audienceClaims` | _[]string_ | AudienceClaim allows to define any claim that is verified against the client id<br/>By default `aud` claim is used for verification. |
| `extraAudiences` | _[]string_ | ExtraAudiences is a list of additional audiences that are allowed<br/>to pass verification in addition to the client id. |
| `enabledSigningAlgs` | _[]string_ | EnabledSigningAlgs is a list of allowed JWT signing algorithms.<br/>When discovery is enabled, the effective set is the intersection<br/>between this list and the provider's discovered supported algorithms.<br/>By default `RS256` is used if nothing has been discovered or specified. |
| `authStyle` | _string_ | AuthStyle specifies how the endpoint wants the client ID & client secret sent.<br/>Possible values are:<br/> - "inParams" (or "params"): sends credentials in the POST body as application/x-www-form-urlencoded parameters<br/> - "inHeader" (or "header"): sends credentials using HTTP Basic Authorization<br/> - "" (empty, default): auto-detect by trying both ways<br/>Some providers like Apple require "inParams". |
### Provider
@ -574,6 +588,7 @@ Provider holds all configuration for a single provider
| `googleConfig` | _[GoogleOptions](#googleoptions)_ | GoogleConfig holds all configurations for Google provider. |
| `oidcConfig` | _[OIDCOptions](#oidcoptions)_ | OIDCConfig holds all configurations for OIDC provider<br/>or providers utilize OIDC configurations. |
| `loginGovConfig` | _[LoginGovOptions](#logingovoptions)_ | LoginGovConfig holds all configurations for LoginGov provider. |
| `appleConfig` | _[AppleOptions](#appleoptions)_ | AppleConfig holds all configurations for Apple provider. |
| `id` | _string_ | ID should be a unique identifier for the provider.<br/>This value is required for all providers. |
| `provider` | _[ProviderType](#providertype)_ | Type is the OAuth provider<br/>must be set from the supported providers group,<br/>otherwise 'Google' is set as default |
| `name` | _string_ | Name is the providers display name<br/>if set, it will be shown to the users in the login page. |

View File

@ -107,7 +107,7 @@ func providerRequiresClientSecret(provider options.Provider) bool {
}
// Apple uses a private key to dynamically generate client_secret JWTs
if provider.Type == "apple" {
if provider.Type == options.AppleProvider {
return false
}

View File

@ -1,7 +1,6 @@
package providers
import (
"context"
"crypto/ecdsa"
"crypto/x509"
"encoding/pem"
@ -11,11 +10,8 @@ import (
"os"
"time"
"github.com/coreos/go-oidc/v3/oidc"
"github.com/golang-jwt/jwt/v5"
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options"
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/sessions"
"github.com/oauth2-proxy/oauth2-proxy/v7/pkg/requests"
"golang.org/x/oauth2"
)
@ -63,14 +59,18 @@ func NewAppleProvider(p *ProviderData, appleOpts options.AppleOptions, oidcOpts
validateURL: nil,
scope: appleDefaultScope,
})
p.getAuthorizationHeaderFunc = makeOIDCHeader
// Apple returns the authorization code via form POST rather than query
// parameters, so default the response mode accordingly
if p.AuthRequestResponseMode == "" {
p.AuthRequestResponseMode = "form_post"
}
oidcProvider := NewOIDCProvider(p, oidcOpts)
// Apple requires the client credentials in the POST body
oidcProvider.AuthStyle = oauth2.AuthStyleInParams
provider := &AppleProvider{
OIDCProvider: &OIDCProvider{
ProviderData: p,
SkipNonce: true, // Apple doesn't use nonce in the standard way
AuthStyle: oauth2.AuthStyleInParams, // Apple requires credentials in POST body
},
OIDCProvider: oidcProvider,
TeamID: appleOpts.TeamID,
KeyID: appleOpts.KeyID,
}
@ -167,34 +167,3 @@ func (p *AppleProvider) generateClientSecret() (string, error) {
return token.SignedString(p.PrivateKey)
}
// GetLoginURL returns the Apple authorization URL with required parameters
func (p *AppleProvider) GetLoginURL(redirectURI, state, nonce string, extraParams url.Values) string {
// Apple requires response_mode=form_post for web clients
if extraParams.Get("response_mode") == "" {
extraParams.Set("response_mode", "form_post")
}
return p.OIDCProvider.GetLoginURL(redirectURI, state, nonce, extraParams)
}
// ValidateSession validates the session's ID token
func (p *AppleProvider) ValidateSession(ctx context.Context, s *sessions.SessionState) bool {
ctx = oidc.ClientContext(ctx, requests.DefaultHTTPClient)
// Validate ID token if present
if s.IDToken != "" && p.Verifier != nil {
if _, err := p.Verifier.Verify(ctx, s.IDToken); err != nil {
return false
}
// ID token is valid - Apple doesn't provide a token validation endpoint
return true
}
// Fallback to access token validation if ValidateURL is set
if p.ValidateURL != nil && p.ValidateURL.String() != "" {
return validateToken(ctx, p, s.AccessToken, makeOIDCHeader(s.AccessToken))
}
// No validation possible, but session exists with valid data
return s.AccessToken != ""
}