Documentation
¶
Index ¶
- type Adapter
- type OAuthTokenProvider
- type StaticTokenProvider
- func (p *StaticTokenProvider) AuthMethod() domain.AuthMethod
- func (p *StaticTokenProvider) GetAccessToken(ctx context.Context) (string, error)
- func (p *StaticTokenProvider) GetCredentials(ctx context.Context) (*domain.Credentials, error)
- func (p *StaticTokenProvider) IsValid(ctx context.Context) bool
- type TokenProviderFactory
- func (f *TokenProviderFactory) Create(ctx context.Context, connectionID string) (driven.TokenProvider, error)
- func (f *TokenProviderFactory) CreateFromConnection(ctx context.Context, conn *domain.Connection) (driven.TokenProvider, error)
- func (f *TokenProviderFactory) RegisterRefresher(platform domain.PlatformType, refresher TokenRefresherFunc)
- func (f *TokenProviderFactory) RemoveProvider(connectionID string)
- type TokenRefresherFunc
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Adapter ¶
type Adapter struct {
// contains filtered or unexported fields
}
Adapter handles authentication operations using bcrypt and JWT
func NewAdapter ¶
NewAdapter creates a new auth adapter with the given JWT secret
func NewAdapterWithCost ¶
NewAdapterWithCost creates a new auth adapter with custom bcrypt cost
func (*Adapter) GenerateToken ¶
func (a *Adapter) GenerateToken(claims *domain.TokenClaims) (string, error)
GenerateToken creates a signed JWT from domain claims
func (*Adapter) HashPassword ¶
HashPassword generates a bcrypt hash from a plaintext password
func (*Adapter) ParseToken ¶
func (a *Adapter) ParseToken(tokenString string) (*domain.TokenClaims, error)
ParseToken validates a JWT and extracts domain claims
func (*Adapter) VerifyPassword ¶
VerifyPassword checks if a password matches a bcrypt hash
type OAuthTokenProvider ¶
type OAuthTokenProvider struct {
// contains filtered or unexported fields
}
OAuthTokenProvider implements TokenProvider for OAuth2 credentials. It is intended to be shared across all consumers of the same connectionID within the process — TokenProviderFactory.Create ensures exactly one instance exists per connection. The embedded mutex serialises token refresh: while one caller is executing the HTTP round-trip to the token endpoint (typically ~200ms), other callers for the same connection block on the lock and then see the fresh token without issuing a second refresh. This prevents the token-endpoint race that occurs when N concurrent goroutines each hold a stale token and all decide to refresh simultaneously, causing Microsoft to rotate the refresh token and invalidate N-1 of the requests.
The mutex is held for the entire duration of the refresh HTTP call. This is an intentional design choice: the alternative (generation counters or refresh-in-flight channels) adds significantly more code for the same outcome. Document this explicitly so future readers do not reach for a singleflight rewrite without considering the trade-off.
Token state divergence: if anything mutates the connection's secrets in Postgres without going through refreshLocked (e.g. a direct DB write), the in-memory provider will go stale until the process restarts or RemoveProvider is called and Create re-loads the connection.
func NewOAuthTokenProvider ¶
func NewOAuthTokenProvider( connectionID string, accessToken string, refreshToken string, expiry *time.Time, refresher TokenRefresherFunc, connectionStore driven.ConnectionStore, ) *OAuthTokenProvider
NewOAuthTokenProvider creates a token provider for OAuth credentials.
func (*OAuthTokenProvider) AuthMethod ¶
func (p *OAuthTokenProvider) AuthMethod() domain.AuthMethod
AuthMethod returns OAuth2.
func (*OAuthTokenProvider) GetAccessToken ¶
func (p *OAuthTokenProvider) GetAccessToken(ctx context.Context) (string, error)
GetAccessToken returns a valid access token, refreshing if needed. It holds mu for the duration of a refresh so that concurrent callers serialise: the second caller blocks until the first refresh completes, then sees needsRefresh() == false and skips a redundant refresh.
func (*OAuthTokenProvider) GetCredentials ¶
func (p *OAuthTokenProvider) GetCredentials(ctx context.Context) (*domain.Credentials, error)
GetCredentials returns credentials for OAuth. It holds mu for the same reason as GetAccessToken.
func (*OAuthTokenProvider) IsValid ¶
func (p *OAuthTokenProvider) IsValid(ctx context.Context) bool
IsValid checks if credentials are valid (not expired or can be refreshed).
This method is lock-free and intentionally so: its contract is best-effort ("has a valid token or can be refreshed"). A concurrent refresh may flip isExpired() from true to false while IsValid runs; the race only makes the result more conservative (returns true when the token was just refreshed), never incorrectly false. Callers that need a guaranteed-valid token must call GetAccessToken instead.
type StaticTokenProvider ¶
type StaticTokenProvider struct {
// contains filtered or unexported fields
}
StaticTokenProvider implements TokenProvider for non-OAuth credentials. Used for API keys, PATs, and service accounts.
func NewStaticTokenProvider ¶
func NewStaticTokenProvider(token string, authMethod domain.AuthMethod) *StaticTokenProvider
NewStaticTokenProvider creates a token provider for static credentials.
func (*StaticTokenProvider) AuthMethod ¶
func (p *StaticTokenProvider) AuthMethod() domain.AuthMethod
AuthMethod returns the authentication method.
func (*StaticTokenProvider) GetAccessToken ¶
func (p *StaticTokenProvider) GetAccessToken(ctx context.Context) (string, error)
GetAccessToken returns the static token.
func (*StaticTokenProvider) GetCredentials ¶
func (p *StaticTokenProvider) GetCredentials(ctx context.Context) (*domain.Credentials, error)
GetCredentials returns nil for static tokens - use GetAccessToken instead.
type TokenProviderFactory ¶
type TokenProviderFactory struct {
// contains filtered or unexported fields
}
TokenProviderFactory creates TokenProviders from connection credentials. It maintains a per-connection cache (providers) so that all callers sharing the same connectionID get the exact same *OAuthTokenProvider instance. This ensures that OAuth token refresh is serialised per connection: only one goroutine refreshes at a time, and subsequent callers see the new token immediately instead of racing the same refresh token.
Cold-start race: if two goroutines call Create for the same connectionID simultaneously before either has populated the cache, both may call connectionStore.Get and construct a provider. Only one wins the LoadOrStore; the loser's instance is GC'd. This costs at most one extra Postgres read per connection per process lifetime and requires no synchronisation beyond the sync.Map itself.
func NewTokenProviderFactory ¶
func NewTokenProviderFactory( connectionStore driven.ConnectionStore, ) *TokenProviderFactory
NewTokenProviderFactory creates a new TokenProviderFactory.
func (*TokenProviderFactory) Create ¶
func (f *TokenProviderFactory) Create(ctx context.Context, connectionID string) (driven.TokenProvider, error)
Create returns a TokenProvider for the given connectionID.
If a provider for connectionID already exists in the process-level cache, it is returned immediately (O(1), no I/O). Otherwise the connection is loaded from the store, a new provider is constructed, and the result is stored via LoadOrStore so concurrent callers converge on a single instance.
func (*TokenProviderFactory) CreateFromConnection ¶
func (f *TokenProviderFactory) CreateFromConnection(ctx context.Context, conn *domain.Connection) (driven.TokenProvider, error)
CreateFromConnection creates a TokenProvider from a connection directly. Use this when you already have the connection loaded. The returned provider is NOT inserted into the per-connection cache — it is a fresh instance scoped to the caller's use (e.g. OAuth callback flows that have the connection in hand before it is registered in the cache).
func (*TokenProviderFactory) RegisterRefresher ¶
func (f *TokenProviderFactory) RegisterRefresher( platform domain.PlatformType, refresher TokenRefresherFunc, )
RegisterRefresher registers a token refresh function for a platform type.
func (*TokenProviderFactory) RemoveProvider ¶ added in v0.3.0
func (f *TokenProviderFactory) RemoveProvider(connectionID string)
RemoveProvider evicts the cached provider for a connection. It should be called by ConnectionService.Delete after the underlying connection row is removed, to prevent stale token state from persisting in memory.
RemoveProvider is a concrete-only method and does not appear on the driven.TokenProviderFactory port interface — callers that only hold the interface are unaffected.
type TokenRefresherFunc ¶
TokenRefresherFunc is a function type for token refresh operations.