-
Notifications
You must be signed in to change notification settings - Fork 1.2k
OAuth2 auto-configuration #5341
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: zibet27/jwk-auto-discover
Are you sure you want to change the base?
OAuth2 auto-configuration #5341
Conversation
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
WalkthroughThe PR extends OpenID Connect support in Ktor's authentication system by adding new properties to OpenIdConfiguration, introducing a new OpenIdOAuthConfig class, and providing new OAuth configuration overloads that accept OpenID configuration for streamlined OpenID-based OAuth flows. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested reviewers
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
🤖 Fix all issues with AI agents
In `@ktor-server/ktor-server-plugins/ktor-server-auth/api/ktor-server-auth.api`:
- Around line 488-493: The two 4-arg Kotlin overloads
oauth(AuthenticationConfig, String, OpenIdConfiguration, Function1) and
oauth(AuthenticationConfig, String, String, Function1) cause Java-call ambiguity
when the third parameter is null; annotate the Kotlin overloads with distinct
JVM names (e.g., add `@JvmName`("oauthWithOpenId") to the OpenIdConfiguration
variant and `@JvmName`("oauthWithClientId") to the String-variant) so the
generated methods have unique JVM signatures and Java callers can unambiguously
invoke the desired overload; apply the annotations to the corresponding oauth
functions (and their default dispatchers if necessary) so the compiled API
exposes disambiguated method names.
In
`@ktor-server/ktor-server-plugins/ktor-server-auth/common/src/io/ktor/server/auth/OAuthProcedure.kt`:
- Around line 193-209: The oauth wrapper leaves
OAuthAuthenticationProvider.Config.client uninitialized when
OpenIdOAuthConfig.client is null, causing UninitializedPropertyAccessException;
fix by ensuring a default HttpClient is provided: in AuthenticationConfig.oauth
(the function in OAuthProcedure.kt) assign this.client = openIdConfig.client ?:
HttpClient() (or alternatively make OpenIdOAuthConfig initialize client to
HttpClient() by default) so the provider's lateinit client is always set before
build(); reference symbols: AuthenticationConfig.oauth, OpenIdOAuthConfig,
OAuthAuthenticationProvider.Config.client.
In
`@ktor-server/ktor-server-plugins/ktor-server-auth/common/src/io/ktor/server/auth/OpenIdOAuthConfig.kt`:
- Around line 63-72: The KDoc for OpenIdOAuthConfig.defaultScopes says it should
default to the intersection of ["openid","profile","email"] with
OpenIdConfiguration.scopesSupported, but the code assigns
openIdConfiguration.scopesSupported directly; update the implementation where
`scopes` is computed (the `scopes = defaultScopes ?:
openIdConfiguration.scopesSupported ?: listOf("openid")` logic) to instead
compute `defaultScopes ?:
(openIdConfiguration.scopesSupported?.intersect(listOf("openid","profile","email"))?.toList())
?: listOf("openid")` so the effective scopes match the documented intersection
with `OpenIdConfiguration.scopesSupported`; alternatively, if you prefer to keep
current behavior, update the KDoc for `defaultScopes` to describe that it uses
`scopesSupported` directly and falls back to ["openid"].
🧹 Nitpick comments (3)
ktor-server/ktor-server-plugins/ktor-server-auth/jvm/test/io/ktor/tests/auth/FetchOpenIdConfigurationTest.kt (1)
121-138: HTTP error handling test is adequate.The test verifies that a 404 response results in a
DiscoveryException. Consider adding a test for network failures or malformed JSON responses for more comprehensive coverage.ktor-server/ktor-server-plugins/ktor-server-auth/common/test/io/ktor/tests/auth/OpenIdOAuthTest.kt (1)
184-205: Validation tests for required configuration fields.These tests ensure that
IllegalArgumentExceptionis thrown when required fields (clientId,clientSecret,urlProvider) are missing. The error messages clearly indicate which field is missing.Note: The
assertFailsWithmessage parameter (e.g.,"clientId must be specified") is a test failure message, not a matcher for the exception message. If you intend to verify the exception message content, useassertTrue(exception.message!!.contains(...))pattern as inFetchOpenIdConfigurationTest.📝 Alternative: Verify exception message content
`@Test` fun testOAuthWithOpenIdConfigurationMissingClientId() { val openIdConfig = OpenIdConfiguration(...) val exception = assertFailsWith<IllegalArgumentException> { testApplication { install(Authentication) { oauth("test-openid", openIdConfig) { client = this@testApplication.client clientSecret = "test-client-secret" urlProvider = { "http://localhost/callback" } } } } } assertTrue(exception.message!!.contains("clientId")) }Also applies to: 207-241
ktor-server/ktor-server-plugins/ktor-server-auth/common/src/io/ktor/server/auth/OpenIdConfiguration.kt (1)
108-130: Validation logic ensures required endpoints are present.The validation checks for blank values rather than just null, which is appropriate since the JSON might contain empty strings. Consider reordering validations to match the property declaration order for consistency (authorizationEndpoint → tokenEndpoint → jwksUri).
♻️ Optional: Reorder validations to match property order
- if (config.jwksUri.isBlank()) { - throw DiscoveryException("OpenID configuration from $issuer is missing jwks_uri") - } if (config.authorizationEndpoint.isBlank()) { throw DiscoveryException("OpenID configuration from $issuer is missing authorization_endpoint") } if (config.tokenEndpoint.isBlank()) { throw DiscoveryException("OpenID configuration from $issuer is missing token_endpoint") } + if (config.jwksUri.isBlank()) { + throw DiscoveryException("OpenID configuration from $issuer is missing jwks_uri") + } return config
| public static final fun oauth (Lio/ktor/server/auth/AuthenticationConfig;Ljava/lang/String;Lio/ktor/server/auth/OpenIdConfiguration;Lkotlin/jvm/functions/Function1;)V | ||
| public static final fun oauth (Lio/ktor/server/auth/AuthenticationConfig;Ljava/lang/String;Ljava/lang/String;Lio/ktor/server/auth/OpenIdConfiguration;Lkotlin/jvm/functions/Function1;)V | ||
| public static final fun oauth (Lio/ktor/server/auth/AuthenticationConfig;Ljava/lang/String;Ljava/lang/String;Lkotlin/jvm/functions/Function1;)V | ||
| public static final fun oauth (Lio/ktor/server/auth/AuthenticationConfig;Ljava/lang/String;Lkotlin/jvm/functions/Function1;)V | ||
| public static synthetic fun oauth$default (Lio/ktor/server/auth/AuthenticationConfig;Ljava/lang/String;Lio/ktor/server/auth/OpenIdConfiguration;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)V | ||
| public static synthetic fun oauth$default (Lio/ktor/server/auth/AuthenticationConfig;Ljava/lang/String;Ljava/lang/String;Lio/ktor/server/auth/OpenIdConfiguration;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)V |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
# Find the OAuth-related source files
fd -e kt -t f oauth | grep -E "(auth|oauth)" | head -20Repository: ktorio/ktor
Length of output: 1041
🏁 Script executed:
# Search for oauth function definitions
rg "fun.*oauth" --type kt -A 5 | head -100Repository: ktorio/ktor
Length of output: 81
🏁 Script executed:
# Look for the main oauth implementation in ktor-server-auth
find . -path "*/ktor-server-auth/*" -name "*.kt" -type f | head -20Repository: ktorio/ktor
Length of output: 2083
🏁 Script executed:
cat ./ktor-server/ktor-server-plugins/ktor-server-auth/jvm/src/io/ktor/server/auth/OAuth.ktRepository: ktorio/ktor
Length of output: 2486
🏁 Script executed:
cat ./ktor-server/ktor-server-plugins/ktor-server-auth/common/src/io/ktor/server/auth/OpenIdConfiguration.ktRepository: ktorio/ktor
Length of output: 5695
🏁 Script executed:
# Search for oauth function definitions - extension functions
rg "fun.*oauth\(" --type-add 'kotlin:*.kt' -t kotlin | head -50Repository: ktorio/ktor
Length of output: 602
🏁 Script executed:
# Check OAuth2.kt which likely contains the oauth extension functions
cat ./ktor-server/ktor-server-plugins/ktor-server-auth/common/src/io/ktor/server/auth/OAuth2.kt | head -200Repository: ktorio/ktor
Length of output: 6610
🏁 Script executed:
cat ./ktor-server/ktor-server-plugins/ktor-server-auth/common/src/io/ktor/server/auth/OAuthProcedure.ktRepository: ktorio/ktor
Length of output: 11535
🏁 Script executed:
# Check if there are any `@JvmName` annotations on the oauth functions
rg "@JvmName" ./ktor-server/ktor-server-plugins/ktor-server-auth/common/src/io/ktor/server/auth/OAuthProcedure.ktRepository: ktorio/ktor
Length of output: 37
🏁 Script executed:
# Look for Java test files that might use the oauth functions
find ./ktor-server/ktor-server-plugins/ktor-server-auth -name "*.java" -type fRepository: ktorio/ktor
Length of output: 37
🏁 Script executed:
# Check if there's an actual overload ambiguity by creating a test case
cat > /tmp/test_ambiguity.kt << 'EOF'
// Simulating the overloads from the actual code
class TestAmbiguity {
interface Config
interface OpenIdOAuthConfig
data class OpenIdConfiguration(val issuer: String)
fun oauth(
config: Any,
name: String? = null,
configure: Config.() -> Unit
) {}
fun oauth(
config: Any,
name: String? = null,
description: String? = null,
configure: Config.() -> Unit
) {}
fun oauth(
config: Any,
name: String? = null,
openIdConfiguration: OpenIdConfiguration,
configure: OpenIdOAuthConfig.() -> Unit
) {}
fun oauth(
config: Any,
name: String? = null,
description: String? = null,
openIdConfiguration: OpenIdConfiguration,
configure: OpenIdOAuthConfig.() -> Unit
) {}
fun test() {
// Test calls
oauth(Any(), "name") {} // Should match first overload
oauth(Any(), "name", null) {} // POTENTIALLY AMBIGUOUS - String or OpenIdConfiguration?
oauth(Any(), "name", null as String?) {} // Should match second overload
oauth(Any(), "name", OpenIdConfiguration("issuer")) {} // Should match third overload
}
}
EOF
cat /tmp/test_ambiguity.ktRepository: ktorio/ktor
Length of output: 1283
🏁 Script executed:
# Let's check the .api file to see what synthetic defaults were generated
grep -A 20 "oauth\$default" ./ktor-server/ktor-server-plugins/ktor-server-auth/api/ktor-server-auth.api | head -30Repository: ktorio/ktor
Length of output: 2122
🏁 Script executed:
# Let's look at the actual parameter types more carefully - check if OpenIdConfiguration is nullable
cat ./ktor-server/ktor-server-plugins/ktor-server-auth/common/src/io/ktor/server/auth/OAuthProcedure.kt | grep -A 10 "fun AuthenticationConfig.oauth"Repository: ktorio/ktor
Length of output: 1700
🏁 Script executed:
# Also check the `@api` file more carefully around the oauth definitions to see full signatures
grep -B 5 -A 10 "fun oauth" ./ktor-server/ktor-server-plugins/ktor-server-auth/api/ktor-server-auth.api | head -50Repository: ktorio/ktor
Length of output: 2176
🏁 Script executed:
# Let's see the exact lines around 488-493 in the api file
sed -n '480,500p' ./ktor-server/ktor-server-plugins/ktor-server-auth/api/ktor-server-auth.apiRepository: ktorio/ktor
Length of output: 2130
🏁 Script executed:
# Let's create a test to see if Kotlin actually allows calling with null and which overload gets picked
cat > /tmp/test_kotlin_overload.kt << 'EOF'
data class OpenIdConfiguration(val issuer: String)
fun test(
name: String? = null,
openIdConfiguration: OpenIdConfiguration,
configure: () -> Unit
) {
println("OpenIdConfiguration overload called")
}
fun test(
name: String? = null,
description: String? = null,
configure: () -> Unit
) {
println("String overload called")
}
fun main() {
// This should be unambiguous because the 3rd parameter type is different
test("name", OpenIdConfiguration("issuer")) {}
// Can we call with null?
// test("name", null) {} // This would be ambiguous!
}
EOF
cat /tmp/test_kotlin_overload.ktRepository: ktorio/ktor
Length of output: 648
🏁 Script executed:
# Check if there are any existing tests for the oauth functions
find ./ktor-server/ktor-server-plugins/ktor-server-auth -name "*Test.kt" -o -name "*Test.java" | xargs grep -l "oauth" 2>/dev/null | head -5Repository: ktorio/ktor
Length of output: 345
🏁 Script executed:
# Look at one of the test files to see how oauth is actually called
cat ./ktor-server/ktor-server-plugins/ktor-server-auth/common/test/io/ktor/tests/auth/OpenIdOAuthTest.kt | head -100Repository: ktorio/ktor
Length of output: 3800
🏁 Script executed:
# Check if the oauth functions in OAuthProcedure.kt have any `@JvmName` annotations
grep -B 2 "fun AuthenticationConfig.oauth" ./ktor-server/ktor-server-plugins/ktor-server-auth/common/src/io/ktor/server/auth/OAuthProcedure.kt | grep -E "@JvmName|fun AuthenticationConfig"Repository: ktorio/ktor
Length of output: 210
🏁 Script executed:
# Let's verify if Java can actually call these functions with null - check for Java test files
find ./ktor-server/ktor-server-plugins/ktor-server-auth -name "*Test.java" -type fRepository: ktorio/ktor
Length of output: 37
🏁 Script executed:
# Check the exact signature by looking at what parameters are required
sed -n '56,170p' ./ktor-server/ktor-server-plugins/ktor-server-auth/common/src/io/ktor/server/auth/OAuthProcedure.ktRepository: ktorio/ktor
Length of output: 5233
🏁 Script executed:
# Let's verify the actual overload ambiguity by checking what Java sees
# Look at the complete function signatures with their parameter counts
cat ./ktor-server/ktor-server-plugins/ktor-server-auth/api/ktor-server-auth.api | grep -A 2 "OAuthProcedureKt"Repository: ktorio/ktor
Length of output: 338
🏁 Script executed:
# Test if Kotlin compiler would accept a call with null for the 3rd parameter
cat > /tmp/test_null_ambiguity.kt << 'EOF'
package test
data class OpenIdConfiguration(val issuer: String)
interface AuthenticationConfig
fun AuthenticationConfig.oauth(
name: String? = null,
openIdConfiguration: OpenIdConfiguration,
configure: (Any) -> Unit
) {
println("OpenId overload")
}
fun AuthenticationConfig.oauth(
name: String? = null,
description: String? = null,
configure: (Any) -> Unit
) {
println("String overload")
}
fun main() {
val config: AuthenticationConfig = object : AuthenticationConfig {}
// Test 1: These should be unambiguous
config.oauth("name", OpenIdConfiguration("issuer")) {} // Clear - OpenId overload
config.oauth("name", "desc") {} // Clear - String overload
// Test 2: What about null?
// config.oauth("name", null) {} // Would this compile?
}
EOF
python3 << 'PYEOF'
# Since we can't actually compile Kotlin, let's reason through the JVM signatures
# and what Java would see
api_lines = [
"oauth (Lio/ktor/server/auth/AuthenticationConfig;Ljava/lang/String;Lio/ktor/server/auth/OpenIdConfiguration;Lkotlin/jvm/functions/Function1;)V",
"oauth (Lio/ktor/server/auth/AuthenticationConfig;Ljava/lang/String;Ljava/lang/String;Lio/ktor/server/auth/OpenIdConfiguration;Lkotlin/jvm/functions/Function1;)V",
"oauth (Lio/ktor/server/auth/AuthenticationConfig;Ljava/lang/String;Ljava/lang/String;Lkotlin/jvm/functions/Function1;)V",
"oauth (Lio/ktor/server/auth/AuthenticationConfig;Ljava/lang/String;Lkotlin/jvm/functions/Function1;)V",
]
print("JVM Signatures for oauth:")
print("=" * 80)
for i, sig in enumerate(api_lines, 1):
# Parse parameter count
params = sig.count("L")
print(f"{i}. Parameters: {params}")
print(f" {sig}")
print()
print("\nAnalysis:")
print("-" * 80)
print("In Java, a call oauth(config, \"name\", null, function) has 4 arguments")
print("\nCan match:")
print(" - Signature 1 (4 params): oauth(..., String, OpenIdConfiguration, Function1)")
print(" - Signature 3 (4 params): oauth(..., String, String, Function1)")
print("\nBoth accept null as 3rd parameter:")
print(" - OpenIdConfiguration (nullable)")
print(" - String (nullable)")
print("\n⚠️ This IS ambiguous in Java!")
PYEOFRepository: ktorio/ktor
Length of output: 1215
Java overload ambiguity with 4-argument oauth calls.
The 4-parameter overloads oauth(AuthenticationConfig, String, OpenIdConfiguration, Function1) and oauth(AuthenticationConfig, String, String, Function1) create ambiguity when called from Java with a null third argument—the compiler cannot determine which overload to invoke since both accept null. Consider adding @JvmName annotations to disambiguate, e.g., @JvmName("oauthWithOpenId") on the OpenIdConfiguration overload.
🤖 Prompt for AI Agents
In `@ktor-server/ktor-server-plugins/ktor-server-auth/api/ktor-server-auth.api`
around lines 488 - 493, The two 4-arg Kotlin overloads
oauth(AuthenticationConfig, String, OpenIdConfiguration, Function1) and
oauth(AuthenticationConfig, String, String, Function1) cause Java-call ambiguity
when the third parameter is null; annotate the Kotlin overloads with distinct
JVM names (e.g., add `@JvmName`("oauthWithOpenId") to the OpenIdConfiguration
variant and `@JvmName`("oauthWithClientId") to the String-variant) so the
generated methods have unique JVM signatures and Java callers can unambiguously
invoke the desired overload; apply the annotations to the corresponding oauth
functions (and their default dispatchers if necessary) so the compiled API
exposes disambiguated method names.
| public fun AuthenticationConfig.oauth( | ||
| name: String? = null, | ||
| description: String? = null, | ||
| openIdConfiguration: OpenIdConfiguration, | ||
| configure: OpenIdOAuthConfig.() -> Unit | ||
| ) { | ||
| val openIdConfig = OpenIdOAuthConfig(openIdConfiguration).apply(configure) | ||
| val urlProviderFn = requireNotNull(openIdConfig.urlProvider) { | ||
| "urlProvider must be specified" | ||
| } | ||
| oauth(name, description) { | ||
| urlProvider = urlProviderFn | ||
| fallback = openIdConfig.fallback | ||
| settings = openIdConfig.toServerSettings() | ||
| openIdConfig.client?.let { this.client = it } | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
git ls-files | grep -E "(OAuthProcedure|OAuthAuthenticationProvider)" | head -20Repository: ktorio/ktor
Length of output: 152
🏁 Script executed:
cat -n ktor-server/ktor-server-plugins/ktor-server-auth/common/src/io/ktor/server/auth/OAuthProcedure.kt | sed -n '1,100p'Repository: ktorio/ktor
Length of output: 4771
🏁 Script executed:
cat -n ktor-server/ktor-server-plugins/ktor-server-auth/common/src/io/ktor/server/auth/OAuthProcedure.kt | sed -n '50,70p'Repository: ktorio/ktor
Length of output: 1194
🏁 Script executed:
cat -n ktor-server/ktor-server-plugins/ktor-server-auth/common/src/io/ktor/server/auth/OAuthProcedure.kt | sed -n '190,220p'Repository: ktorio/ktor
Length of output: 1507
🏁 Script executed:
cat -n ktor-server/ktor-server-plugins/ktor-server-auth/common/src/io/ktor/server/auth/OAuthProcedure.kt | sed -n '100,193p'Repository: ktorio/ktor
Length of output: 4780
🏁 Script executed:
# Search for other oauth function definitions to understand patterns
rg -A 8 'public fun AuthenticationConfig\.oauth' ktor-server/ktor-server-plugins/ktor-server-auth/common/src/io/ktor/server/auth/OAuthProcedure.ktRepository: ktorio/ktor
Length of output: 1212
🏁 Script executed:
# Check if there's validation of client in build() or elsewhere
rg -B 3 -A 5 'fun build' ktor-server/ktor-server-plugins/ktor-server-auth/common/src/io/ktor/server/auth/OAuthProcedure.ktRepository: ktorio/ktor
Length of output: 442
🏁 Script executed:
# Find OpenIdOAuthConfig class definition
rg -B 5 -A 20 'class OpenIdOAuthConfig' ktor-server/ktor-server-plugins/ktor-server-auth/common/src/io/ktor/server/auth/Repository: ktorio/ktor
Length of output: 3580
🏁 Script executed:
# Check if HttpClient() can be instantiated without parameters and what it creates
rg -B 3 -A 3 'HttpClient\(\)' ktor-server/ktor-server-plugins/ktor-server-auth/common/src/io/ktor/server/auth/OAuthProcedure.ktRepository: ktorio/ktor
Length of output: 37
🏁 Script executed:
# Look for how HttpClient is typically instantiated in Ktor auth module
fd '\.kt$' ktor-server/ktor-server-plugins/ktor-server-auth/ --exec grep -l 'HttpClient()' {} \;Repository: ktorio/ktor
Length of output: 157
🏁 Script executed:
# Check the toServerSettings() method to see if it handles default client
rg -B 5 -A 15 'fun toServerSettings' ktor-server/ktor-server-plugins/ktor-server-auth/common/src/io/ktor/server/auth/Repository: ktorio/ktor
Length of output: 3252
🏁 Script executed:
# Look at the full OpenIdOAuthConfig class
cat -n ktor-server/ktor-server-plugins/ktor-server-auth/common/src/io/ktor/server/auth/OpenIdOAuthConfig.ktRepository: ktorio/ktor
Length of output: 7079
🏁 Script executed:
cat -n ktor-server/ktor-server-plugins/ktor-server-auth/common/src/io/ktor/server/auth/OAuthProcedure.kt | sed -n '203,209p'Repository: ktorio/ktor
Length of output: 324
Uninitialized client property causes runtime crash when omitted from OpenID configuration.
When openIdConfig.client is null (the default), line 207 does not assign a client to the provider config. However, OAuthAuthenticationProvider.Config.client is a lateinit var (line 58) that the constructor (line 32) directly accesses without validation. The build() method does not validate client initialization, resulting in UninitializedPropertyAccessException at runtime.
Additionally, the OpenIdOAuthConfig documentation states the client "Defaults to a new [HttpClient] instance" (line 28), but this is not actually implemented.
Fix: Provide a default HttpClient() when client is not specified:
Proposed fix
oauth(name, description) {
urlProvider = urlProviderFn
fallback = openIdConfig.fallback
settings = openIdConfig.toServerSettings()
- openIdConfig.client?.let { this.client = it }
+ this.client = openIdConfig.client ?: HttpClient()
}🤖 Prompt for AI Agents
In
`@ktor-server/ktor-server-plugins/ktor-server-auth/common/src/io/ktor/server/auth/OAuthProcedure.kt`
around lines 193 - 209, The oauth wrapper leaves
OAuthAuthenticationProvider.Config.client uninitialized when
OpenIdOAuthConfig.client is null, causing UninitializedPropertyAccessException;
fix by ensuring a default HttpClient is provided: in AuthenticationConfig.oauth
(the function in OAuthProcedure.kt) assign this.client = openIdConfig.client ?:
HttpClient() (or alternatively make OpenIdOAuthConfig initialize client to
HttpClient() by default) so the provider's lateinit client is always set before
build(); reference symbols: AuthenticationConfig.oauth, OpenIdOAuthConfig,
OAuthAuthenticationProvider.Config.client.
| /** | ||
| * OAuth scopes to request during authorization. | ||
| * | ||
| * If not set, defaults to intersection of ["openid", "profile", "email"] with | ||
| * [OpenIdConfiguration.scopesSupported]. If [OpenIdConfiguration.scopesSupported] is null, | ||
| * defaults to ["openid"]. | ||
| * | ||
| * [Report a problem](https://ktor.io/feedback/?fqname=io.ktor.server.auth.OpenIdOAuthConfig.defaultScopes) | ||
| */ | ||
| public var defaultScopes: List<String>? = null |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Documentation doesn't match implementation for scope fallback behavior.
The KDoc states: "defaults to intersection of ['openid', 'profile', 'email'] with [OpenIdConfiguration.scopesSupported]"
However, the implementation at Line 132 uses scopesSupported directly without filtering:
val scopes = defaultScopes ?: openIdConfiguration.scopesSupported ?: listOf("openid")Either update the documentation to reflect the actual behavior, or implement the intersection logic as documented.
📝 Option 1: Update documentation to match implementation
/**
* OAuth scopes to request during authorization.
*
- * If not set, defaults to intersection of ["openid", "profile", "email"] with
- * [OpenIdConfiguration.scopesSupported]. If [OpenIdConfiguration.scopesSupported] is null,
- * defaults to ["openid"].
+ * If not set, defaults to [OpenIdConfiguration.scopesSupported] if available,
+ * otherwise defaults to ["openid"].
*🤖 Prompt for AI Agents
In
`@ktor-server/ktor-server-plugins/ktor-server-auth/common/src/io/ktor/server/auth/OpenIdOAuthConfig.kt`
around lines 63 - 72, The KDoc for OpenIdOAuthConfig.defaultScopes says it
should default to the intersection of ["openid","profile","email"] with
OpenIdConfiguration.scopesSupported, but the code assigns
openIdConfiguration.scopesSupported directly; update the implementation where
`scopes` is computed (the `scopes = defaultScopes ?:
openIdConfiguration.scopesSupported ?: listOf("openid")` logic) to instead
compute `defaultScopes ?:
(openIdConfiguration.scopesSupported?.intersect(listOf("openid","profile","email"))?.toList())
?: listOf("openid")` so the effective scopes match the documented intersection
with `OpenIdConfiguration.scopesSupported`; alternatively, if you prefer to keep
current behavior, update the KDoc for `defaultScopes` to describe that it uses
`scopesSupported` directly and falls back to ["openid"].
Subsystem
Server Auth
Motivation
KTOR-8596 OpenID Connect (OAuth2) auto-discover & configuration
Also see KTOR-8595 Auth JWK Support (auto-discover)
#5339
Solution
New DSL