Skip to content
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

AuthorizationServerMetadataResolver queries the issuer for openid-configuration when authorization_servers is defined in issuer metadata #58

Open
srosenda opened this issue Jul 11, 2024 · 4 comments

Comments

@srosenda
Copy link
Contributor

According to the OpenID4VCI specification the OpenID configuration should be queried only if the credential issuer metadata does not include the authorization_servers parameter.

11.2.3. Credential Issuer Metadata Parameters

  • authorization_servers: OPTIONAL. Array of strings, where each string is an identifier of the OAuth 2.0 Authorization Server (as defined in [RFC8414]) the Credential Issuer relies on for authorization. If this parameter is omitted, the entity providing the Credential Issuer is also acting as the Authorization Server, i.e., the Credential Issuer's identifier is used to obtain the Authorization Server metadata. The actual OAuth 2.0 Authorization Server metadata is obtained from the oauth-authorization-server well-known location as defined in Section 3 of [RFC8414].

Furthermore the logic in the code ignores the defined authorization_servers completely if it is able to obtain the OpenID configuration from the issuer.

See

public func resolve(
url: URL
) async -> Result<IdentityAndAccessManagementMetadata, Error> {
if let oidc = await fetchOIDCProviderMetadata(
fetcher: oidcFetcher,
url: url
) {
return .success(.oidc(oidc))
} else if let oauth = await fetchAuthorizationServerMetadata(
fetcher: oauthFetcher,
url: url
) {
return .success(.oauth(oauth))
}
return .failure(ValidationError.error(reason: "Unable to fetch metadata"))
}

and
guard let insertedUrl = modifyURL(
url: url,
modificationType: .appendPathComponents(".well-known", "openid-configuration")
) else {
return nil
}
return try await fetcher.fetch(
url: insertedUrl
).get()

@srosenda srosenda changed the title AuthorizationServerMetadataResolver queries the issuer for openid-configuration when authorization_servers is defined AuthorizationServerMetadataResolver queries the issuer for openid-configuration when authorization_servers is defined in issuer metadata Jul 11, 2024
@dtsiflit
Copy link
Contributor

dtsiflit commented Oct 8, 2024

Thank you for your feedback @srosenda! Based on the logic related to metadata retrieval, we believe we are conforming to the spec. It seems the part you're referencing may be in the metadata decoding, where we fallback to the credential issuer if we cannot locate an auth server.

public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
// Decode each property as necessary, handling optionals and conversions.
credentialIssuerIdentifier = try container.decode(CredentialIssuerId.self, forKey: .credentialIssuerIdentifier)
let servers = try? container.decode([URL].self, forKey: .authorizationServers)
authorizationServers = servers ?? [credentialIssuerIdentifier.url]
credentialEndpoint = try container.decode(CredentialIssuerEndpoint.self, forKey: .credentialEndpoint)

That being said, if this fallback mechanism is not clear to readers, we can implement this directly at the resolver level. We'd be happy to submit a PR on our side, or review and accept a PR from your end to address this.

@srosenda
Copy link
Contributor Author

I understand the OpenID4VCI specification text (which is the same also in draft14 and the current editor's draft) so that openid-configuration should not be queried from the credential issuer if authorization_servers are defined in the issuer metadata. The problems with the current implementation are:

  1. AuthorizationServerMetadataResolver.resolve queries the credential issuer for openid-configuration unconditionally
  2. The information whether authorization_servers were or were not defined in issuer metadata is lost with the fallback mechanism in CredentialIssuerMetadata.init(from:).
  3. If the credential issuer defines authorization_servers in its metadata and also implements the .well-known/openid-configuration resource the library will pick the latter over the <authorization_servers element>/.well-known/oauth-authorization-server that should be used when authorization_servers is defined.

If I run the our wallet implementation under Instruments and record HTTP traffic from OpenID4VCI issuance, I can see two requests to <credential issuer id>/.well-known/openid-configuration, although the issuer metadata defines an authorization server in authorization_servers. Both OpenID configuration requests fail with 404, as the issuer does not provide the .well-known/openid-configuration resource. To my understanding of the specification text the OpenID configuration requests should not be made, because authorization_servers is defined and the unnecessary requests slow down the issuance process and consume the device battery and user data plan.

@srosenda
Copy link
Contributor Author

Re-reading the specification once more it also explicitly states that the Authorization Server metadata is obtained from the oauth-authorization-server well-known location as defined in Section 3 of [RFC8414]. The .well-known/openid-configuration is a legacy location for obtaining the authorization metadata, described in Section 5 of [RFC8414], so querying .well-known/openid-configuration seems to be outside OpenID4VCI specification altogether.

@dtsiflit
Copy link
Contributor

Thank you so much for your comprehensive analysis on this srosenda . I'll be following up here soon.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants