package providers import ( "net/url" "strings" "time" ) // AzureProvider encapsulates Azure AD-specific OIDC logic. type AzureProvider struct { *BaseProvider } // NewAzureProvider creates a new instance of the AzureProvider. func NewAzureProvider() *AzureProvider { return &AzureProvider{ BaseProvider: NewBaseProvider(), } } // GetType returns the provider's type. func (p *AzureProvider) GetType() ProviderType { return ProviderTypeAzure } // GetCapabilities returns the specific capabilities of the Azure provider. func (p *AzureProvider) GetCapabilities() ProviderCapabilities { return ProviderCapabilities{ SupportsRefreshTokens: true, RequiresOfflineAccessScope: true, PreferredTokenValidation: "access", } } // BuildAuthParams configures Azure-specific authentication parameters. func (p *AzureProvider) BuildAuthParams(baseParams url.Values, scopes []string) (*AuthParams, error) { baseParams.Set("response_mode", "query") hasOfflineAccess := false for _, scope := range scopes { if scope == ScopeOfflineAccess { hasOfflineAccess = true break } } if !hasOfflineAccess { scopes = append(scopes, ScopeOfflineAccess) } return &AuthParams{ URLValues: baseParams, Scopes: deduplicateScopes(scopes), }, nil } // Azure may use access tokens for validation, and this method ensures that behavior is preserved. func (p *AzureProvider) ValidateTokens(session Session, verifier TokenVerifier, tokenCache TokenCache, refreshGracePeriod time.Duration) (*ValidationResult, error) { if !session.GetAuthenticated() { if session.GetRefreshToken() != "" { return &ValidationResult{NeedsRefresh: true}, nil } return &ValidationResult{IsExpired: true}, nil } accessToken := session.GetAccessToken() idToken := session.GetIDToken() if accessToken != "" { if strings.Count(accessToken, ".") == 2 { if err := verifier.VerifyToken(accessToken); err != nil { if idToken != "" { return p.ValidateTokenExpiry(session, idToken, tokenCache, refreshGracePeriod) } if session.GetRefreshToken() != "" { return &ValidationResult{NeedsRefresh: true}, nil } return &ValidationResult{IsExpired: true}, nil } return p.ValidateTokenExpiry(session, accessToken, tokenCache, refreshGracePeriod) } if idToken != "" { return p.ValidateTokenExpiry(session, idToken, tokenCache, refreshGracePeriod) } return &ValidationResult{Authenticated: true}, nil } if idToken != "" { if err := verifier.VerifyToken(idToken); err != nil { if session.GetRefreshToken() != "" { return &ValidationResult{NeedsRefresh: true}, nil } return &ValidationResult{IsExpired: true}, nil } return p.ValidateTokenExpiry(session, idToken, tokenCache, refreshGracePeriod) } if session.GetRefreshToken() != "" { return &ValidationResult{NeedsRefresh: true}, nil } return &ValidationResult{IsExpired: true}, nil } // Azure requires specific tenant configuration and scope handling. func (p *AzureProvider) ValidateConfig() error { return p.BaseProvider.ValidateConfig() }