Fix TypeScript compilation errors in multi-provider implementation

- Fix OAuth2ClientWithConfig to properly extend arctic OAuth2Client
- Rename methods to avoid base class conflicts (exchangeAuthorizationCode, refreshTokens)
- Fix OAuth2ProviderManager to use OBPClientService.get() correctly
- Fix iteration over Map entries to avoid downlevelIteration issues
- Update OAuth2ConnectController with correct method signatures
- Fix redirect URI access via getRedirectUri() method
This commit is contained in:
simonredfern 2025-12-28 15:28:42 +01:00
parent 0eace070f9
commit e701522734
4 changed files with 40 additions and 28 deletions

View File

@ -205,7 +205,7 @@ export class OAuth2CallbackController {
// Exchange code for tokens
console.log(`OAuth2CallbackController: Exchanging authorization code for tokens`)
const tokens = await client.validateAuthorizationCode(code, codeVerifier)
const tokens = await client.exchangeAuthorizationCode(code, codeVerifier)
// Store tokens in session
session.oauth2_access_token = tokens.accessToken

View File

@ -169,14 +169,14 @@ export class OAuth2ConnectController {
session.oauth2_state = state
// Use legacy service to create authorization URL
const authUrl = this.legacyOAuth2Service.createAuthorizationURL(state, codeVerifier, [
const authUrl = this.legacyOAuth2Service.createAuthorizationURL(state, [
'openid',
'profile',
'email'
])
console.log('OAuth2ConnectController: Redirecting to legacy OIDC provider')
return response.redirect(authUrl)
return response.redirect(authUrl.toString())
}
/**
@ -186,7 +186,7 @@ export class OAuth2ConnectController {
const authEndpoint = client.getAuthorizationEndpoint()
const params = new URLSearchParams({
client_id: client.clientId,
redirect_uri: client.redirectURI,
redirect_uri: client.getRedirectUri(),
response_type: 'code',
scope: 'openid profile email',
state: state,

View File

@ -25,7 +25,7 @@
*
*/
import { OAuth2Client } from 'arctic'
import { OAuth2Client, OAuth2Tokens } from 'arctic'
import type { OIDCConfiguration, TokenResponse } from '../types/oauth2.js'
/**
@ -48,10 +48,14 @@ import type { OIDCConfiguration, TokenResponse } from '../types/oauth2.js'
export class OAuth2ClientWithConfig extends OAuth2Client {
public OIDCConfig?: OIDCConfiguration
public provider: string
private _clientSecret: string
private _redirectUri: string
constructor(clientId: string, clientSecret: string, redirectUri: string, provider: string) {
super(clientId, clientSecret, redirectUri)
this.provider = provider
this._clientSecret = clientSecret
this._redirectUri = redirectUri
}
/**
@ -158,16 +162,15 @@ export class OAuth2ClientWithConfig extends OAuth2Client {
}
/**
* Validate authorization code and exchange for tokens
* Exchange authorization code for tokens
*
* This method extends the base OAuth2Client functionality to support
* provider-specific token exchange requirements (e.g., Basic Auth vs form-based credentials)
* This method provides a simpler interface for token exchange
*
* @param code - Authorization code from OIDC provider
* @param codeVerifier - PKCE code verifier
* @returns Token response with access token, refresh token, and ID token
*/
async validateAuthorizationCode(code: string, codeVerifier: string): Promise<TokenResponse> {
async exchangeAuthorizationCode(code: string, codeVerifier: string): Promise<TokenResponse> {
const tokenEndpoint = this.getTokenEndpoint()
console.log(`OAuth2ClientWithConfig: Exchanging authorization code for ${this.provider}`)
@ -176,19 +179,19 @@ export class OAuth2ClientWithConfig extends OAuth2Client {
const body = new URLSearchParams({
grant_type: 'authorization_code',
code: code,
redirect_uri: this.redirectURI,
redirect_uri: this._redirectUri,
code_verifier: codeVerifier,
client_id: this.clientId
})
// Add client_secret to body (some providers prefer this over Basic Auth)
if (this.clientSecret) {
body.append('client_secret', this.clientSecret)
if (this._clientSecret) {
body.append('client_secret', this._clientSecret)
}
try {
// Try with Basic Authentication first (RFC 6749 standard)
const authHeader = Buffer.from(`${this.clientId}:${this.clientSecret}`).toString('base64')
const authHeader = Buffer.from(`${this.clientId}:${this._clientSecret}`).toString('base64')
const response = await fetch(tokenEndpoint, {
method: 'POST',
@ -229,7 +232,7 @@ export class OAuth2ClientWithConfig extends OAuth2Client {
* @param refreshToken - Refresh token from previous authentication
* @returns New token response
*/
async refreshAccessToken(refreshToken: string): Promise<TokenResponse> {
async refreshTokens(refreshToken: string): Promise<TokenResponse> {
const tokenEndpoint = this.getTokenEndpoint()
console.log(`OAuth2ClientWithConfig: Refreshing access token for ${this.provider}`)
@ -240,12 +243,12 @@ export class OAuth2ClientWithConfig extends OAuth2Client {
client_id: this.clientId
})
if (this.clientSecret) {
body.append('client_secret', this.clientSecret)
if (this._clientSecret) {
body.append('client_secret', this._clientSecret)
}
try {
const authHeader = Buffer.from(`${this.clientId}:${this.clientSecret}`).toString('base64')
const authHeader = Buffer.from(`${this.clientId}:${this._clientSecret}`).toString('base64')
const response = await fetch(tokenEndpoint, {
method: 'POST',
@ -279,4 +282,18 @@ export class OAuth2ClientWithConfig extends OAuth2Client {
throw error
}
}
/**
* Get the redirect URI
*/
getRedirectUri(): string {
return this._redirectUri
}
/**
* Get the client secret
*/
getClientSecret(): string {
return this._clientSecret
}
}

View File

@ -77,12 +77,7 @@ export class OAuth2ProviderManager {
try {
// Use OBPClientService to call the API
const response = await this.obpClientService.call<WellKnownResponse>(
'GET',
'/obp/v5.1.0/well-known',
null,
null
)
const response = await this.obpClientService.get('/obp/v5.1.0/well-known', null)
if (!response.well_known_uris || response.well_known_uris.length === 0) {
console.warn('OAuth2ProviderManager: No well-known URIs found in OBP API response')
@ -90,7 +85,7 @@ export class OAuth2ProviderManager {
}
console.log(`OAuth2ProviderManager: Found ${response.well_known_uris.length} providers:`)
response.well_known_uris.forEach((uri) => {
response.well_known_uris.forEach((uri: WellKnownUri) => {
console.log(` - ${uri.provider}: ${uri.url}`)
})
@ -219,9 +214,9 @@ export class OAuth2ProviderManager {
const checkPromises: Promise<void>[] = []
for (const [providerName, client] of this.providers.entries()) {
this.providers.forEach((client, providerName) => {
checkPromises.push(this.checkProviderHealth(providerName, client))
}
})
await Promise.allSettled(checkPromises)
}
@ -288,11 +283,11 @@ export class OAuth2ProviderManager {
getAvailableProviders(): string[] {
const available: string[] = []
for (const [name, status] of this.providerStatus.entries()) {
this.providerStatus.forEach((status, name) => {
if (status.available && this.providers.has(name)) {
available.push(name)
}
}
})
return available
}