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

Add a way to check what protocols are supported #168

Open
marcoscaceres opened this issue Sep 12, 2024 · 7 comments
Open

Add a way to check what protocols are supported #168

marcoscaceres opened this issue Sep 12, 2024 · 7 comments
Assignees
Labels
cgr1-blocker Community Group Report 1 Blocker

Comments

@marcoscaceres
Copy link
Collaborator

It's currently not possible to check what protocols the browser supports so developers won't know if calling .get() will immediately fail (as it requires user activation).

As such, we should then add a. static setlike.supportedProtocols With the sequence, a developer can easily filter with standard Set methods.

Proposed API addition

interface DigitalCredentialsSupportedProtocols {
  readonly setlike<DOMString>; // user agent pre-populates
};

partial interface DigitalCredential {
   readonly attribute DigitalCredentialsSupportedProtocols supportedProtocols;
}

Usage:

if (DigitalCredential.supportedProtocols.has("openid4vp")) {
  // let's make an openid4vp request
}

// Or you can do...
const supported = Array.from(DigitalCredential.supportedProtocols).filter(typesTheRPSupports);

// Or whatever developers want:
for (const supported in DigitalCredential.supportedProtocols.values()) {
   // do things with supported
}

const requests = [...DigitalCredential.supportedProtocols].map(toRequestWeKnowHowToMake);

// or even... 
switch (true) {
   case DigitalCredential.supportedProtocols.has("openid4vp"):
      makeOpenIDRequest(data);
      break;
   case DigitalCredential.supportedProtocols.has("whatever"):
      makeWhateverRequest(data);
      break;
   default:
     throw TypeError("Oh noes! they don't support our favorite protocol!")
}

That gives a ton of flexibility. You can even use it will all the new fancy JavaScript set comparison operations:

// DigitalCredential.supportedProtocols is a Set
const supportedProtocols = DigitalCredential.supportedProtocols;

// Example Set of protocols to compare
const protocolsToCheck = new Set(['openid4vp', 'someOtherProtocol']);

// Union: Combining both sets
const union = supportedProtocols.union(protocolsToCheck);
console.log(union); // Set { 'openid4vp', 'someOtherProtocol', ... }

// Intersection: Getting common protocols between the sets
const intersection = supportedProtocols.intersection(protocolsToCheck);
console.log(intersection); // Set { 'openid4vp' }

// Difference: Getting protocols supported by DigitalCredential but not in protocolsToCheck
const difference = supportedProtocols.difference(protocolsToCheck);
console.log(difference); // Set { ... } (protocols supported by DigitalCredential but not in protocolsToCheck)

// Symmetric Difference: Getting protocols that are in either set, but not in both
const symmetricDifference = supportedProtocols.symmetricDifference(protocolsToCheck);
console.log(symmetricDifference); // Set { 'someOtherProtocol', ... }
@msporny
Copy link
Contributor

msporny commented Sep 13, 2024

+1, this is a useful feature to have to ensure that user journeys don't end abruptly when the desired protocol isn't supported.

@timcappalli timcappalli added the cgr1-blocker Community Group Report 1 Blocker label Sep 18, 2024
@timcappalli timcappalli added this to the Community Group Report 1 milestone Sep 19, 2024
@leecam
Copy link
Collaborator

leecam commented Oct 3, 2024

Ideally I'd like browsers on Android to pass the request through and let the OS decide what protocols are supported. So its unclear how a browser could return this list on Android.

I think a isProtocolSupported() method might be better. On Android this would likely always return true.

If we keep this I think it will be very hard for the community to develop or improve the protocols. Lets say OpenID wanted to start work on 'openid4vp_v2'. Today with Chrome/Android they can just start developing and testing it. All they need to do it create a wallet and test website that supports and they can get real implementation experience and iterate before committing it to a stable spec.

We're actually doing that this week by implementing the new query language for openid4vp_v1.1. They need multiple implementations to gain some real world feedback before they can commit to a spec, so we are adding support for it to our wallets and test websites to exercise it. This doesn't require any changes to Android or Chrome.

If we add this API, then browsers couldn't list openid4vp_v1.1 or openid4vp_v2.0 etc...does this mean they shouldn't pass them through? In that case we couldn't iterate on spec proposals without browsers and OSs being in the same iteration loop.

So my recommendation would be to not return a list, but change to a isProtocolSupported('opendi4vp') method. Then on android the browser can defer that question to the platform.

@npdoty
Copy link

npdoty commented Oct 7, 2024

Boolean testing is often preferred to providing a set for privacy reasons.

Also a privacy risk though if the test/set reveals any configuration-specific information (whether you have installed a particular wallet that supports a particular feature, etc.), so we should warn against that if we do support this.

@MasterKale
Copy link

MasterKale commented Oct 7, 2024

It's currently not possible to check what protocols the browser supports so developers won't know if calling .get() will immediately fail (as it requires user activation).

What about an API similar to WebAuthn L3's getClientCapabilities()?

https://w3c.github.io/webauthn/#sctn-getClientCapabilities

Spitballing a bit here, it might look something like this:

const { openid4vp, whatever } = await DigitalCredential.getClientCapabilities();

if (openid4vp) {
  const cred = await navigator.credentials.get({ digital: { ... } });
} else if (whatever) {
  const cred = await someCustomPresentationAPI({ ... });
}

Also a privacy risk though if the test/set reveals any configuration-specific information (whether you have installed a particular wallet that supports a particular feature, etc.), so we should warn against that if we do support this.

There's accommodations in PublicKeyCredential.getClientCapabilities() for browsers to omit certain capabilities for sake of user privacy; I don't see why those same accommodations couldn't be carried over into a Digital Credentials-specific version of the method.

And others can foresee paired use of WebAuthn + Digital Credentials for certain use cases in the future, it might be nice for developers to have similar methods to call in either domain 🤔

So my recommendation would be to not return a list, but change to a isProtocolSupported('opendi4vp') method. Then on android the browser can defer that question to the platform.

To @leecam's question, a getClientCapabilities() method would give browsers a chance to query the platform "just in time" to understand available capabilities too.

@samuelgoto
Copy link
Collaborator

@marcoscaceres and I chatted briefly about this today and so far we think this could work between Chrome and Safari if we introduced the notion of a pre-defined value of * or any to mean "the browser accepts any protocol" (such that Chrome can expose * and Safari reserves the right to skip it).

@timcappalli
Copy link
Member

That seems... messy to be honest. What were the concerns with the method taking an input parameter with a protocol name?

@samuelgoto
Copy link
Collaborator

That seems... messy to be honest. What were the concerns with the method taking an input parameter with a protocol name?

Ah, I remembered why @marcoscaceres and I arrived at *: Chrome allows any protocol to be used, whereas Safari allows some, and it seemed important that Verifiers know the difference between the two in an interoperable way.

Specifically, Chrome deliberately wants to allow protocols to be extensible, so that innovation can happen in this space without it being a blocker.

So, if we go with a a static setlike supportedProtocols as @marcoscaceres proposed, there needs to be an entry there that represents this specific difference between the two implementations.

If we go with getters, we wouldn't need to specify *, which would work too, I think.

I don't personally feel strongly which way we go, just wanted to raise that there is an important distinction between Chrome's implementation and Safari's implementation that's important to expose to developers in an interoperable way.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
cgr1-blocker Community Group Report 1 Blocker
Projects
None yet
Development

No branches or pull requests

7 participants