diff --git a/sdk/keyvault/azure-security-keyvault-certificates/pom.xml b/sdk/keyvault/azure-security-keyvault-certificates/pom.xml
index b12616654d9b..36f6c171c82e 100644
--- a/sdk/keyvault/azure-security-keyvault-certificates/pom.xml
+++ b/sdk/keyvault/azure-security-keyvault-certificates/pom.xml
@@ -127,6 +127,7 @@
--add-exports com.azure.core/com.azure.core.implementation.http=ALL-UNNAMED
--add-opens com.azure.security.keyvault.certificates/com.azure.security.keyvault.certificates=ALL-UNNAMED
+ --add-opens com.azure.security.keyvault.certificates/com.azure.security.keyvault.certificates.models=ALL-UNNAMED
diff --git a/sdk/keyvault/azure-security-keyvault-certificates/src/main/java/com/azure/security/keyvault/certificates/CertificateClientBuilder.java b/sdk/keyvault/azure-security-keyvault-certificates/src/main/java/com/azure/security/keyvault/certificates/CertificateClientBuilder.java
index 5c1c2e8d97e2..7f43800009e3 100644
--- a/sdk/keyvault/azure-security-keyvault-certificates/src/main/java/com/azure/security/keyvault/certificates/CertificateClientBuilder.java
+++ b/sdk/keyvault/azure-security-keyvault-certificates/src/main/java/com/azure/security/keyvault/certificates/CertificateClientBuilder.java
@@ -19,6 +19,7 @@
import com.azure.core.util.Configuration;
import com.azure.core.util.logging.ClientLogger;
import com.azure.security.keyvault.certificates.implementation.KeyVaultCredentialPolicy;
+import com.azure.security.keyvault.certificates.models.KeyVaultCertificateIdentifier;
import java.net.MalformedURLException;
import java.net.URL;
@@ -162,7 +163,9 @@ public CertificateAsyncClient buildAsyncClient() {
/**
* Sets the vault endpoint url to send HTTP requests to.
*
- * @param vaultUrl The vault endpoint url is used as destination on Azure to send requests to.
+ * @param vaultUrl The vault endpoint url is used as destination on Azure to send requests to. If you have a
+ * certificate identifier, use {@link KeyVaultCertificateIdentifier#parse(String)} to parse it and obtain the
+ * {@code vaultUrl} and other information.
* @return the updated ServiceClientBuilder object.
* @throws IllegalArgumentException if {@code vaultUrl} is null or it cannot be parsed into a valid URL.
*/
diff --git a/sdk/keyvault/azure-security-keyvault-certificates/src/main/java/com/azure/security/keyvault/certificates/models/KeyVaultCertificateIdentifier.java b/sdk/keyvault/azure-security-keyvault-certificates/src/main/java/com/azure/security/keyvault/certificates/models/KeyVaultCertificateIdentifier.java
new file mode 100644
index 000000000000..493181645d99
--- /dev/null
+++ b/sdk/keyvault/azure-security-keyvault-certificates/src/main/java/com/azure/security/keyvault/certificates/models/KeyVaultCertificateIdentifier.java
@@ -0,0 +1,105 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+package com.azure.security.keyvault.certificates.models;
+
+import com.azure.security.keyvault.certificates.CertificateAsyncClient;
+import com.azure.security.keyvault.certificates.CertificateClient;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+
+/**
+ * Information about a {@link KeyVaultCertificate} parsed from the certificate URL. You can use this information when
+ * calling methods of {@link CertificateClient} or {@link CertificateAsyncClient}.
+ */
+public final class KeyVaultCertificateIdentifier {
+ private final String certificateId, vaultUrl, name, version;
+
+ private KeyVaultCertificateIdentifier(String certificateId, String vaultUrl, String name, String version) {
+ this.certificateId = certificateId;
+ this.vaultUrl = vaultUrl;
+ this.name = name;
+ this.version = version;
+ }
+
+ /**
+ * Gets the key identifier used to create this object
+ *
+ * @return The certificate identifier.
+ */
+ public String getCertificateId() {
+ return certificateId;
+ }
+
+ /**
+ * Gets the URL of the Key Vault.
+ *
+ * @return The Key Vault URL.
+ */
+ public String getVaultUrl() {
+ return vaultUrl;
+ }
+
+ /**
+ * Gets the name of the certificate.
+ *
+ * @return The certificate name.
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Gets the optional version of the certificate.
+ *
+ * @return The certificate version.
+ */
+ public String getVersion() {
+ return version;
+ }
+
+ /**
+ * Create a new {@link KeyVaultCertificateIdentifier} from a given certificate identifier.
+ *
+ *
Valid examples are:
+ *
+ *
+ * - https://{key-vault-name}.vault.azure.net/certificates/{certificate-name}
+ * - https://{key-vault-name}.vault.azure.net/certificates/{certificate-name}/pending
+ * - https://{key-vault-name}.vault.azure.net/certificates/{certificate-name}/{unique-version-id}
+ * - https://{key-vault-name}.vault.azure.net/deletedcertificates/{deleted-certificate-name}
+ *
+ *
+ * @param certificateId The certificate identifier to extract information from.
+ * @return a new instance of {@link KeyVaultCertificateIdentifier}.
+ * @throws IllegalArgumentException if the given identifier is {@code null} or an invalid Key Vault Certificate
+ * identifier.
+ */
+ public static KeyVaultCertificateIdentifier parse(String certificateId) throws IllegalArgumentException {
+ if (certificateId == null) {
+ throw new IllegalArgumentException("certificateId cannot be null");
+ }
+
+ try {
+ final URL url = new URL(certificateId);
+ // We expect an identifier with either 2 or 3 path segments: collection + name [+ version]
+ final String[] pathSegments = url.getPath().split("/");
+
+ if ((pathSegments.length != 3 && pathSegments.length != 4) // More or less segments in the URI than expected.
+ || !"https".equals(url.getProtocol()) // Invalid protocol.
+ || (!"certificates".equals(pathSegments[1]) && !"deletedcertificates".equals(pathSegments[1])) // Invalid collection.
+ || ("deletedcertificates".equals(pathSegments[1]) && pathSegments.length == 4)) { // Deleted items do not include a version.
+ throw new IllegalArgumentException("certificateId is not a valid Key Vault Certificate identifier");
+ }
+
+ final String vaultUrl = String.format("%s://%s", url.getProtocol(), url.getHost());
+ final String certificateName = pathSegments[2];
+ final String certificateVersion = pathSegments.length == 4 ? pathSegments[3] : null;
+
+ return new KeyVaultCertificateIdentifier(certificateId, vaultUrl, certificateName, certificateVersion);
+ } catch (MalformedURLException e) {
+ throw new IllegalArgumentException("Could not parse certificateId", e);
+ }
+ }
+}
diff --git a/sdk/keyvault/azure-security-keyvault-certificates/src/test/java/com/azure/security/keyvault/certificates/models/KeyVaultCertificateIdentifierTest.java b/sdk/keyvault/azure-security-keyvault-certificates/src/test/java/com/azure/security/keyvault/certificates/models/KeyVaultCertificateIdentifierTest.java
new file mode 100644
index 000000000000..371f16920bec
--- /dev/null
+++ b/sdk/keyvault/azure-security-keyvault-certificates/src/test/java/com/azure/security/keyvault/certificates/models/KeyVaultCertificateIdentifierTest.java
@@ -0,0 +1,83 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+package com.azure.security.keyvault.certificates.models;
+
+import org.junit.jupiter.api.Test;
+
+import java.net.MalformedURLException;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+class KeyVaultCertificateIdentifierTest {
+ @Test
+ void parseWithoutVersion() throws MalformedURLException {
+ String certificateId = "https://test-key-vault.vault.azure.net/certificates/test-certificate";
+ KeyVaultCertificateIdentifier keyVaultCertificateIdentifier =
+ KeyVaultCertificateIdentifier.parse(certificateId);
+
+ assertEquals(certificateId, keyVaultCertificateIdentifier.getCertificateId());
+ assertEquals("https://test-key-vault.vault.azure.net", keyVaultCertificateIdentifier.getVaultUrl());
+ assertEquals("test-certificate", keyVaultCertificateIdentifier.getName());
+ assertNull(keyVaultCertificateIdentifier.getVersion());
+ }
+
+ @Test
+ void parseWithVersion() throws MalformedURLException {
+ String certificateId = "https://test-key-vault.vault.azure.net/certificates/test-certificate/version";
+ KeyVaultCertificateIdentifier keyVaultCertificateIdentifier =
+ KeyVaultCertificateIdentifier.parse(certificateId);
+
+ assertEquals(certificateId, keyVaultCertificateIdentifier.getCertificateId());
+ assertEquals("https://test-key-vault.vault.azure.net", keyVaultCertificateIdentifier.getVaultUrl());
+ assertEquals("test-certificate", keyVaultCertificateIdentifier.getName());
+ assertEquals("version", keyVaultCertificateIdentifier.getVersion());
+ }
+
+ @Test
+ void parseForDeletedCertificate() throws MalformedURLException {
+ String certificateId = "https://test-key-vault.vault.azure.net/deletedcertificates/test-certificate";
+ KeyVaultCertificateIdentifier keyVaultCertificateIdentifier = KeyVaultCertificateIdentifier.parse(certificateId);
+
+ assertEquals(certificateId, keyVaultCertificateIdentifier.getCertificateId());
+ assertEquals("https://test-key-vault.vault.azure.net", keyVaultCertificateIdentifier.getVaultUrl());
+ assertEquals("test-certificate", keyVaultCertificateIdentifier.getName());
+ }
+
+ @Test
+ void parseInvalidIdentifierForDeletedCertificate() {
+ String certificateId = "https://test-key-vault.vault.azure.net/deletedcertificates/test-certificate/version";
+ Exception exception = assertThrows(IllegalArgumentException.class,
+ () -> KeyVaultCertificateIdentifier.parse(certificateId));
+
+ assertEquals("certificateId is not a valid Key Vault Certificate identifier", exception.getMessage());
+ }
+
+ @Test
+ void parseNullIdentifier() {
+ Exception exception = assertThrows(IllegalArgumentException.class,
+ () -> KeyVaultCertificateIdentifier.parse(null));
+
+ assertEquals("certificateId cannot be null", exception.getMessage());
+ }
+
+ @Test
+ void parseInvalidIdentifierWithWrongCollection() {
+ String certificateId = "https://test-key-vault.vault.azure.net/keys/test-certificate";
+ Exception exception = assertThrows(IllegalArgumentException.class,
+ () -> KeyVaultCertificateIdentifier.parse(certificateId));
+
+ assertEquals("certificateId is not a valid Key Vault Certificate identifier", exception.getMessage());
+ }
+
+ @Test
+ void parseInvalidIdentifierWithExtraSegment() {
+ String certificateId = "https://test-key-vault.vault.azure.net/keys/test-certificate/version/extra-segment";
+ Exception exception = assertThrows(IllegalArgumentException.class,
+ () -> KeyVaultCertificateIdentifier.parse(certificateId));
+
+ assertEquals("certificateId is not a valid Key Vault Certificate identifier", exception.getMessage());
+ }
+}
diff --git a/sdk/keyvault/azure-security-keyvault-keys/pom.xml b/sdk/keyvault/azure-security-keyvault-keys/pom.xml
index 8d9903091077..add790fd73f8 100644
--- a/sdk/keyvault/azure-security-keyvault-keys/pom.xml
+++ b/sdk/keyvault/azure-security-keyvault-keys/pom.xml
@@ -134,6 +134,7 @@
--add-opens com.azure.security.keyvault.keys/com.azure.security.keyvault.keys=ALL-UNNAMED
--add-opens com.azure.security.keyvault.keys/com.azure.security.keyvault.keys.cryptography=ALL-UNNAMED
+ --add-opens com.azure.security.keyvault.keys/com.azure.security.keyvault.keys.models=ALL-UNNAMED
diff --git a/sdk/keyvault/azure-security-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/KeyClientBuilder.java b/sdk/keyvault/azure-security-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/KeyClientBuilder.java
index b58733b35d9d..de657f8fbff8 100644
--- a/sdk/keyvault/azure-security-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/KeyClientBuilder.java
+++ b/sdk/keyvault/azure-security-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/KeyClientBuilder.java
@@ -19,6 +19,8 @@
import com.azure.core.util.CoreUtils;
import com.azure.core.util.logging.ClientLogger;
import com.azure.security.keyvault.keys.implementation.KeyVaultCredentialPolicy;
+import com.azure.security.keyvault.keys.models.KeyVaultKeyIdentifier;
+
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
@@ -163,7 +165,9 @@ public KeyAsyncClient buildAsyncClient() {
/**
* Sets the vault url to send HTTP requests to.
*
- * @param vaultUrl The vault url is used as destination on Azure to send requests to.
+ * @param vaultUrl The vault url is used as destination on Azure to send requests to. If you have a key identifier,
+ * use {@link KeyVaultKeyIdentifier#parse(String)} to parse it and obtain the {@code vaultUrl} and other
+ * information.
* @return the updated ServiceClientBuilder object.
* @throws IllegalArgumentException if {@code vaultUrl} is null or it cannot be parsed into a valid URL.
*/
diff --git a/sdk/keyvault/azure-security-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/models/KeyVaultKeyIdentifier.java b/sdk/keyvault/azure-security-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/models/KeyVaultKeyIdentifier.java
new file mode 100644
index 000000000000..683c30997e19
--- /dev/null
+++ b/sdk/keyvault/azure-security-keyvault-keys/src/main/java/com/azure/security/keyvault/keys/models/KeyVaultKeyIdentifier.java
@@ -0,0 +1,104 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+package com.azure.security.keyvault.keys.models;
+
+import com.azure.security.keyvault.keys.KeyAsyncClient;
+import com.azure.security.keyvault.keys.KeyClient;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+
+/**
+ * Information about a {@link KeyVaultKey} parsed from the key URL. You can use this information when calling methods
+ * of {@link KeyClient} or {@link KeyAsyncClient}.
+ */
+public final class KeyVaultKeyIdentifier {
+ private final String keyId, vaultUrl, name, version;
+
+ private KeyVaultKeyIdentifier(String keyId, String vaultUrl, String name, String version) {
+ this.keyId = keyId;
+ this.vaultUrl = vaultUrl;
+ this.name = name;
+ this.version = version;
+ }
+
+ /**
+ * Gets the key identifier used to create this object.
+ *
+ * @return The key identifier.
+ */
+ public String getKeyId() {
+ return keyId;
+ }
+
+ /**
+ * Gets the URL of the Key Vault.
+ *
+ * @return The Key Vault URL.
+ */
+ public String getVaultUrl() {
+ return vaultUrl;
+ }
+
+ /**
+ * Gets the name of the key.
+ *
+ * @return The key name.
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Gets the optional version of the key.
+ *
+ * @return The key version.
+ */
+ public String getVersion() {
+ return version;
+ }
+
+ /**
+ * Create a new {@link KeyVaultKeyIdentifier} from a given key identifier.
+ *
+ * Valid examples are:
+ *
+ *
+ * - https://{key-vault-name}.vault.azure.net/keys/{key-name}
+ * - https://{key-vault-name}.vault.azure.net/keys/{key-name}/pending
+ * - https://{key-vault-name}.vault.azure.net/keys/{key-name}/{unique-version-id}
+ * - https://{key-vault-name}.vault.azure.net/deletedkeys/{deleted-key-name}
+ *
+ *
+ * @param keyId The key identifier to extract information from.
+ * @return a new instance of {@link KeyVaultKeyIdentifier}.
+ * @throws IllegalArgumentException if the given identifier is {@code null} or an invalid Key Vault Key identifier.
+ */
+ public static KeyVaultKeyIdentifier parse(String keyId) throws IllegalArgumentException {
+ if (keyId == null) {
+ throw new IllegalArgumentException("keyId cannot be null");
+ }
+
+ try {
+ final URL url = new URL(keyId);
+ // We expect an identifier with either 2 or 3 path segments: collection + name [+ version]
+ final String[] pathSegments = url.getPath().split("/");
+
+ if ((pathSegments.length != 3 && pathSegments.length != 4) // More or less segments in the URI than expected.
+ || !"https".equals(url.getProtocol()) // Invalid protocol.
+ || (!"keys".equals(pathSegments[1]) && !"deletedkeys".equals(pathSegments[1])) // Invalid collection.
+ || ("deletedkeys".equals(pathSegments[1]) && pathSegments.length == 4)) { // Deleted items do not include a version.
+ throw new IllegalArgumentException("keyId is not a valid Key Vault Key identifier");
+ }
+
+ final String vaultUrl = String.format("%s://%s", url.getProtocol(), url.getHost());
+ final String keyName = pathSegments[2];
+ final String keyVersion = pathSegments.length == 4 ? pathSegments[3] : null;
+
+ return new KeyVaultKeyIdentifier(keyId, vaultUrl, keyName, keyVersion);
+ } catch (MalformedURLException e) {
+ throw new IllegalArgumentException("Could not parse keyId", e);
+ }
+ }
+}
diff --git a/sdk/keyvault/azure-security-keyvault-keys/src/test/java/com/azure/security/keyvault/keys/models/KeyVaultKeyIdentifierTest.java b/sdk/keyvault/azure-security-keyvault-keys/src/test/java/com/azure/security/keyvault/keys/models/KeyVaultKeyIdentifierTest.java
new file mode 100644
index 000000000000..0b067d469305
--- /dev/null
+++ b/sdk/keyvault/azure-security-keyvault-keys/src/test/java/com/azure/security/keyvault/keys/models/KeyVaultKeyIdentifierTest.java
@@ -0,0 +1,77 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+package com.azure.security.keyvault.keys.models;
+
+import org.junit.jupiter.api.Test;
+
+import java.net.MalformedURLException;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+class KeyVaultKeyIdentifierTest {
+ @Test
+ void parseWithoutVersion() throws MalformedURLException {
+ String keyId = "https://test-key-vault.vault.azure.net/keys/test-key";
+ KeyVaultKeyIdentifier keyVaultKeyIdentifier = KeyVaultKeyIdentifier.parse(keyId);
+
+ assertEquals(keyId, keyVaultKeyIdentifier.getKeyId());
+ assertEquals("https://test-key-vault.vault.azure.net", keyVaultKeyIdentifier.getVaultUrl());
+ assertEquals("test-key", keyVaultKeyIdentifier.getName());
+ assertNull(keyVaultKeyIdentifier.getVersion());
+ }
+
+ @Test
+ void parseWithVersion() throws MalformedURLException {
+ String keyId = "https://test-key-vault.vault.azure.net/keys/test-key/version";
+ KeyVaultKeyIdentifier keyVaultkeyIdentifier = KeyVaultKeyIdentifier.parse(keyId);
+
+ assertEquals(keyId, keyVaultkeyIdentifier.getKeyId());
+ assertEquals("https://test-key-vault.vault.azure.net", keyVaultkeyIdentifier.getVaultUrl());
+ assertEquals("test-key", keyVaultkeyIdentifier.getName());
+ assertEquals("version", keyVaultkeyIdentifier.getVersion());
+ }
+
+ @Test
+ void parseForDeletedKey() throws MalformedURLException {
+ String keyId = "https://test-key-vault.vault.azure.net/deletedkeys/test-key";
+ KeyVaultKeyIdentifier keyVaultKeyIdentifier = KeyVaultKeyIdentifier.parse(keyId);
+
+ assertEquals(keyId, keyVaultKeyIdentifier.getKeyId());
+ assertEquals("https://test-key-vault.vault.azure.net", keyVaultKeyIdentifier.getVaultUrl());
+ assertEquals("test-key", keyVaultKeyIdentifier.getName());
+ }
+
+ @Test
+ void parseInvalidIdentifierForDeletedKey() {
+ String keyId = "https://test-key-vault.vault.azure.net/deletedkeys/test-key/version";
+ Exception exception = assertThrows(IllegalArgumentException.class, () -> KeyVaultKeyIdentifier.parse(keyId));
+
+ assertEquals("keyId is not a valid Key Vault Key identifier", exception.getMessage());
+ }
+
+ @Test
+ void parseNullIdentifier() {
+ Exception exception = assertThrows(IllegalArgumentException.class, () -> KeyVaultKeyIdentifier.parse(null));
+
+ assertEquals("keyId cannot be null", exception.getMessage());
+ }
+
+ @Test
+ void parseInvalidIdentifierWithWrongCollection() {
+ String keyId = "https://test-key-vault.vault.azure.net/secrets/test-key";
+ Exception exception = assertThrows(IllegalArgumentException.class, () -> KeyVaultKeyIdentifier.parse(keyId));
+
+ assertEquals("keyId is not a valid Key Vault Key identifier", exception.getMessage());
+ }
+
+ @Test
+ void parseInvalidIdentifierWithExtraSegment() {
+ String keyId = "https://test-key-vault.vault.azure.net/keys/test-key/version/extra";
+ Exception exception = assertThrows(IllegalArgumentException.class, () -> KeyVaultKeyIdentifier.parse(keyId));
+
+ assertEquals("keyId is not a valid Key Vault Key identifier", exception.getMessage());
+ }
+}
diff --git a/sdk/keyvault/azure-security-keyvault-secrets/pom.xml b/sdk/keyvault/azure-security-keyvault-secrets/pom.xml
index 0e92b0619a20..ea0e09f4963c 100644
--- a/sdk/keyvault/azure-security-keyvault-secrets/pom.xml
+++ b/sdk/keyvault/azure-security-keyvault-secrets/pom.xml
@@ -134,6 +134,7 @@
--add-exports com.azure.core/com.azure.core.implementation.http=ALL-UNNAMED
--add-opens com.azure.security.keyvault.secrets/com.azure.security.keyvault.secrets=ALL-UNNAMED
+ --add-opens com.azure.security.keyvault.secrets/com.azure.security.keyvault.secrets.models=ALL-UNNAMED
diff --git a/sdk/keyvault/azure-security-keyvault-secrets/src/main/java/com/azure/security/keyvault/secrets/SecretClientBuilder.java b/sdk/keyvault/azure-security-keyvault-secrets/src/main/java/com/azure/security/keyvault/secrets/SecretClientBuilder.java
index 669720ee1341..5a530a705d2d 100644
--- a/sdk/keyvault/azure-security-keyvault-secrets/src/main/java/com/azure/security/keyvault/secrets/SecretClientBuilder.java
+++ b/sdk/keyvault/azure-security-keyvault-secrets/src/main/java/com/azure/security/keyvault/secrets/SecretClientBuilder.java
@@ -19,6 +19,7 @@
import com.azure.core.util.CoreUtils;
import com.azure.core.util.logging.ClientLogger;
import com.azure.security.keyvault.secrets.implementation.KeyVaultCredentialPolicy;
+import com.azure.security.keyvault.secrets.models.KeyVaultSecretIdentifier;
import java.net.MalformedURLException;
import java.net.URL;
@@ -166,7 +167,9 @@ public SecretAsyncClient buildAsyncClient() {
/**
* Sets the vault url to send HTTP requests to.
*
- * @param vaultUrl The vault url is used as destination on Azure to send requests to.
+ * @param vaultUrl The vault url is used as destination on Azure to send requests to. If you have a secret
+ * identifier, use {@link KeyVaultSecretIdentifier#parse(String)} to parse it and obtain the {@code vaultUrl} and
+ * other information.
* @return the updated {@link SecretClientBuilder} object.
* @throws IllegalArgumentException if {@code vaultUrl} is null or it cannot be parsed into a valid URL.
*/
diff --git a/sdk/keyvault/azure-security-keyvault-secrets/src/main/java/com/azure/security/keyvault/secrets/models/KeyVaultSecretIdentifier.java b/sdk/keyvault/azure-security-keyvault-secrets/src/main/java/com/azure/security/keyvault/secrets/models/KeyVaultSecretIdentifier.java
new file mode 100644
index 000000000000..8192ac6aeede
--- /dev/null
+++ b/sdk/keyvault/azure-security-keyvault-secrets/src/main/java/com/azure/security/keyvault/secrets/models/KeyVaultSecretIdentifier.java
@@ -0,0 +1,105 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+package com.azure.security.keyvault.secrets.models;
+
+import com.azure.security.keyvault.secrets.SecretAsyncClient;
+import com.azure.security.keyvault.secrets.SecretClient;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+
+/**
+ * Information about a {@link KeyVaultSecret} parsed from the secret URL. You can use this information when calling
+ * methods of {@link SecretClient} or {@link SecretAsyncClient}.
+ */
+public final class KeyVaultSecretIdentifier {
+ private final String secretId, vaultUrl, name, version;
+
+ private KeyVaultSecretIdentifier(String secretId, String vaultUrl, String name, String version) {
+ this.secretId = secretId;
+ this.vaultUrl = vaultUrl;
+ this.name = name;
+ this.version = version;
+ }
+
+ /**
+ * Gets the key identifier used to create this object
+ *
+ * @return The secret identifier.
+ */
+ public String getSecretId() {
+ return secretId;
+ }
+
+ /**
+ * Gets the URL of the Key Vault.
+ *
+ * @return The Key Vault URL.
+ */
+ public String getVaultUrl() {
+ return vaultUrl;
+ }
+
+ /**
+ * Gets the name of the secret.
+ *
+ * @return The secret name.
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Gets the optional version of the secret.
+ *
+ * @return The secret version.
+ */
+ public String getVersion() {
+ return version;
+ }
+
+ /**
+ * Create a new {@link KeyVaultSecretIdentifier} from a given secret identifier.
+ *
+ * Valid examples are:
+ *
+ *
+ * - https://{key-vault-name}.vault.azure.net/secrets/{secret-name}
+ * - https://{key-vault-name}.vault.azure.net/secrets/{secret-name}/pending
+ * - https://{key-vault-name}.vault.azure.net/secrets/{secret-name}/{unique-version-id}
+ * - https://{key-vault-name}.vault.azure.net/deletedsecrets/{deleted-secret-name}
+ *
+ *
+ * @param secretId The secret identifier to extract information from.
+ * @return a new instance of {@link KeyVaultSecretIdentifier}.
+ * @throws IllegalArgumentException if the given identifier is {@code null} or an invalid Key Vault Secret
+ * identifier.
+ */
+ public static KeyVaultSecretIdentifier parse(String secretId) throws IllegalArgumentException {
+ if (secretId == null) {
+ throw new IllegalArgumentException("secretId cannot be null");
+ }
+
+ try {
+ final URL url = new URL(secretId);
+ // We expect an identifier with either 2 or 3 path segments: collection + name [+ version]
+ final String[] pathSegments = url.getPath().split("/");
+
+ if ((pathSegments.length != 3 && pathSegments.length != 4) // More or less segments in the URI than expected.
+ || !"https".equals(url.getProtocol()) // Invalid protocol.
+ || (!"secrets".equals(pathSegments[1]) && !"deletedsecrets".equals(pathSegments[1])) // Invalid collection.
+ || ("deletedsecrets".equals(pathSegments[1]) && pathSegments.length == 4)) { // Deleted items do not include a version.
+ throw new IllegalArgumentException("secretId is not a valid Key Vault Secret identifier");
+ }
+
+ final String vaultUrl = String.format("%s://%s", url.getProtocol(), url.getHost());
+ final String secretName = pathSegments[2];
+ final String secretVersion = pathSegments.length == 4 ? pathSegments[3] : null;
+
+ return new KeyVaultSecretIdentifier(secretId, vaultUrl, secretName, secretVersion);
+ } catch (MalformedURLException e) {
+ throw new IllegalArgumentException("Could not parse secretId", e);
+ }
+ }
+}
diff --git a/sdk/keyvault/azure-security-keyvault-secrets/src/test/java/com/azure/security/keyvault/secrets/models/KeyVaultSecretIdentifierTest.java b/sdk/keyvault/azure-security-keyvault-secrets/src/test/java/com/azure/security/keyvault/secrets/models/KeyVaultSecretIdentifierTest.java
new file mode 100644
index 000000000000..c3c1f4f50add
--- /dev/null
+++ b/sdk/keyvault/azure-security-keyvault-secrets/src/test/java/com/azure/security/keyvault/secrets/models/KeyVaultSecretIdentifierTest.java
@@ -0,0 +1,79 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+package com.azure.security.keyvault.secrets.models;
+
+import org.junit.jupiter.api.Test;
+
+import java.net.MalformedURLException;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+class KeyVaultSecretIdentifierTest {
+ @Test
+ void parseWithoutVersion() throws MalformedURLException {
+ String secretId = "https://test-key-vault.vault.azure.net/secrets/test-secret";
+ KeyVaultSecretIdentifier keyVaultSecretIdentifier = KeyVaultSecretIdentifier.parse(secretId);
+
+ assertEquals(secretId, keyVaultSecretIdentifier.getSecretId());
+ assertEquals("https://test-key-vault.vault.azure.net", keyVaultSecretIdentifier.getVaultUrl());
+ assertEquals("test-secret", keyVaultSecretIdentifier.getName());
+ assertNull(keyVaultSecretIdentifier.getVersion());
+ }
+
+ @Test
+ void parseWithVersion() throws MalformedURLException {
+ String secretId = "https://test-key-vault.vault.azure.net/secrets/test-secret/version";
+ KeyVaultSecretIdentifier keyVaultSecretIdentifier = KeyVaultSecretIdentifier.parse(secretId);
+
+ assertEquals(secretId, keyVaultSecretIdentifier.getSecretId());
+ assertEquals("https://test-key-vault.vault.azure.net", keyVaultSecretIdentifier.getVaultUrl());
+ assertEquals("test-secret", keyVaultSecretIdentifier.getName());
+ assertEquals("version", keyVaultSecretIdentifier.getVersion());
+ }
+
+ @Test
+ void parseForDeletedSecret() throws MalformedURLException {
+ String secretId = "https://test-key-vault.vault.azure.net/deletedsecrets/test-secret";
+ KeyVaultSecretIdentifier keyVaultSecretIdentifier = KeyVaultSecretIdentifier.parse(secretId);
+
+ assertEquals(secretId, keyVaultSecretIdentifier.getSecretId());
+ assertEquals("https://test-key-vault.vault.azure.net", keyVaultSecretIdentifier.getVaultUrl());
+ assertEquals("test-secret", keyVaultSecretIdentifier.getName());
+ }
+
+ @Test
+ void parseInvalidIdentifierForDeletedSecret() {
+ String secretId = "https://test-key-vault.vault.azure.net/deletedsecrets/test-secret/version";
+ Exception exception = assertThrows(IllegalArgumentException.class, () -> KeyVaultSecretIdentifier.parse(secretId));
+
+ assertEquals("secretId is not a valid Key Vault Secret identifier", exception.getMessage());
+ }
+
+ @Test
+ void parseNullIdentifier() {
+ Exception exception = assertThrows(IllegalArgumentException.class, () -> KeyVaultSecretIdentifier.parse(null));
+
+ assertEquals("secretId cannot be null", exception.getMessage());
+ }
+
+ @Test
+ void parseInvalidIdentifierWithWrongCollection() {
+ String secretId = "https://test-key-vault.vault.azure.net/certificates/test-secret";
+ Exception exception = assertThrows(IllegalArgumentException.class,
+ () -> KeyVaultSecretIdentifier.parse(secretId));
+
+ assertEquals("secretId is not a valid Key Vault Secret identifier", exception.getMessage());
+ }
+
+ @Test
+ void parseInvalidIdentifierWithExtraSegment() {
+ String secretId = "https://test-key-vault.vault.azure.net/secrets/test-secret/version/extra";
+ Exception exception = assertThrows(IllegalArgumentException.class,
+ () -> KeyVaultSecretIdentifier.parse(secretId));
+
+ assertEquals("secretId is not a valid Key Vault Secret identifier", exception.getMessage());
+ }
+}