Skip to content

Commit

Permalink
feat: implement custom URL scheme for AuthorizationRequest
Browse files Browse the repository at this point in the history
as described here: https://openid.net/specs/openid-connect-self-issued-v2-1_0.html#name-a-set-of-static-configuratio

This implementation uses `openid` as the defautl custom URL scheme, but it can
by the user.
  • Loading branch information
nanderstabel committed Mar 12, 2024
1 parent d9c7c9b commit dd0bb4c
Show file tree
Hide file tree
Showing 5 changed files with 17 additions and 5 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ This workspace includes Rust implementations for the following DCP specification
| -------------------| ------------------------------------------ | -------
| [OID4VCI](oid4vci) | OpenID for Verifiable Credential Issuance | [Editor's Draft published: 30 August 2023](https://github.com/openid/OpenID4VCI/blob/111db260b1ad1915ca1462cc4904781beb179972/openid-4-verifiable-credential-issuance-1_0.md)
| [OID4VP](oid4vp) | OpenID for Verifiable Presentations | [Working Group Draft 20 published: 29 November 2023](https://openid.net/specs/openid-4-verifiable-presentations-1_0-20.html)
| [SIOPv2](siopv2) | Self-Issued OpenID Provider v2 | [Editor's Draft published: 24 August 2023](https://github.com/openid/SIOPv2/blob/fb00ab840daa0cec614691b712e28c1f77ed43ea/openid-connect-self-issued-v2-1_0.md)
| [SIOPv2](siopv2) | Self-Issued OpenID Provider v2 | [Working Group Draft 13 published: 28 November 2023](https://openid.net/specs/openid-connect-self-issued-v2-1_0-13.html)

### DIF Presentation Exchange

Expand Down
12 changes: 8 additions & 4 deletions oid4vc-core/src/authorization_request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ impl Body for ByValue {
/// form of a [`Body`] which can be [`ByValue`], [`ByReference`], or an [`Object`].
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
pub struct AuthorizationRequest<B: Body> {
#[serde(skip)]
pub custom_url_scheme: String,
#[serde(flatten)]
pub body: B,
}
Expand All @@ -100,6 +102,7 @@ impl<E: Extension + OpenID4VC> AuthorizationRequest<Object<E>> {
original: &AuthorizationRequest<Object<Generic>>,
) -> anyhow::Result<AuthorizationRequest<Object<E>>> {
Ok(AuthorizationRequest {
custom_url_scheme: original.custom_url_scheme.clone(),
body: Object::from_generic(&original.body)?,
})
}
Expand Down Expand Up @@ -130,15 +133,15 @@ impl<B: Body + DeserializeOwned> std::str::FromStr for AuthorizationRequest<B> {
_ => None,
})
.collect::<Result<_, anyhow::Error>>()?;
let authorization_request: AuthorizationRequest<B> = serde_json::from_value(serde_json::Value::Object(map))?;
let mut authorization_request: AuthorizationRequest<B> =
serde_json::from_value(serde_json::Value::Object(map))?;
authorization_request.custom_url_scheme = url.scheme().to_string();
Ok(authorization_request)
}
}

/// In order to convert a [`AuthorizationRequest`] to a string, we need to convert all the values to strings. This is because
/// `serde_urlencoded` does not support serializing non-primitive types.
// TODO: Find a way to dynamically generate the `siopv2://idtoken?` part of the URL. This will require some refactoring
// for the `AuthorizationRequest` struct.
impl<B: Body> std::fmt::Display for AuthorizationRequest<B> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let map: JsonObject = json!(self)
Expand All @@ -155,7 +158,7 @@ impl<B: Body> std::fmt::Display for AuthorizationRequest<B> {
.collect();

let encoded = serde_urlencoded::to_string(map).map_err(|_| std::fmt::Error)?;
write!(f, "siopv2://idtoken?{}", encoded)
write!(f, "{}://?{}", self.custom_url_scheme, encoded)
}
}

Expand All @@ -167,6 +170,7 @@ mod tests {
#[test]
fn test() {
let authorization_request = AuthorizationRequest::<Object> {
custom_url_scheme: "test".to_string(),
body: Object {
rfc7519_claims: Default::default(),
client_id: "did:example:123".to_string(),
Expand Down
1 change: 1 addition & 0 deletions oid4vc-manager/tests/siopv2/implicit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ async fn test_implicit_flow() {

// Create a new RequestUrl which includes a `request_uri` pointing to the mock server's `request_uri` endpoint.
let authorization_request = AuthorizationRequest::<ByReference> {
custom_url_scheme: "openid".to_string(),
body: ByReference {
client_id: "did:test:relyingparty".to_string(),
request_uri: format!("{server_url}/request_uri").parse::<url::Url>().unwrap(),
Expand Down
3 changes: 3 additions & 0 deletions oid4vp/src/authorization_request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ pub struct AuthorizationRequestBuilder {
response_mode: Option<String>,
nonce: Option<String>,
client_metadata: Option<ClientMetadataEnum<ClientMetadataParameters>>,
custom_url_scheme: Option<String>,
}

impl AuthorizationRequestBuilder {
Expand All @@ -79,6 +80,7 @@ impl AuthorizationRequestBuilder {
builder_fn!(state, String);
builder_fn!(presentation_definition, PresentationDefinition);
builder_fn!(client_id_scheme, ClientIdScheme);
builder_fn!(custom_url_scheme, String);

pub fn build(mut self) -> Result<AuthorizationRequest<Object<OID4VP>>> {
match (self.client_id.take(), self.is_empty()) {
Expand All @@ -101,6 +103,7 @@ impl AuthorizationRequestBuilder {
};

Ok(AuthorizationRequest::<Object<OID4VP>> {
custom_url_scheme: self.custom_url_scheme.take().unwrap_or("openid".to_string()),
body: Object::<OID4VP> {
rfc7519_claims: self.rfc7519_claims,
client_id,
Expand Down
4 changes: 4 additions & 0 deletions siopv2/src/authorization_request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ pub struct AuthorizationRequestBuilder {
nonce: Option<String>,
claims: Option<Result<ClaimRequests>>,
client_metadata: Option<ClientMetadataEnum<ClientMetadataParameters>>,
custom_url_scheme: Option<String>,
}

impl AuthorizationRequestBuilder {
Expand All @@ -91,6 +92,7 @@ impl AuthorizationRequestBuilder {
builder_fn!(nonce, String);
builder_fn!(client_metadata, ClientMetadataEnum<ClientMetadataParameters>);
builder_fn!(state, String);
builder_fn!(custom_url_scheme, String);

pub fn build(mut self) -> Result<AuthorizationRequest<Object<SIOPv2>>> {
match (self.client_id.take(), self.is_empty()) {
Expand All @@ -112,6 +114,7 @@ impl AuthorizationRequestBuilder {
};

Ok(AuthorizationRequest::<Object<SIOPv2>> {
custom_url_scheme: self.custom_url_scheme.take().unwrap_or("openid".to_string()),
body: Object::<SIOPv2> {
rfc7519_claims: self.rfc7519_claims,
client_id,
Expand Down Expand Up @@ -184,6 +187,7 @@ mod tests {
assert_eq!(
request_url,
AuthorizationRequest::<Object<SIOPv2>> {
custom_url_scheme: "openid".to_string(),
body: Object::<SIOPv2> {
rfc7519_claims: RFC7519Claims::default(),
client_id: "did:example:123".to_string(),
Expand Down

0 comments on commit dd0bb4c

Please sign in to comment.