Microsoft Entra Verified ID umfasst die REST-API für den Anforderungsdienst. Mit dieser API können Sie Zugangsdaten ausstellen und überprüfen. In diesem Artikel erfahren Sie, wie Sie mit der Verwendung der REST-API für den Anforderungsdienst beginnen.
API-Zugriffstoken
Ihre Anwendung muss ein gültiges Zugriffstoken mit den erforderlichen Berechtigungen enthalten, damit sie auf die REST-API des Request Services zugreifen kann. Die von Microsoft Identity Platform ausgestellten Zugriffstoken enthalten Informationen (Bereiche), welche die Anforderungsdienst-REST-API verwendet, um die aufrufende Person zu überprüfen. Ein Zugriffstoken stellt sicher, dass der Aufrufer über die richtigen Berechtigungen zum Ausführen des angeforderten Vorgangs verfügt.
Um ein Zugriffstoken zu erhalten, muss Ihre App bei der Microsoft Identity Platform registriert und von einem Administrator für den Zugriff auf die Anforderungsdienst-REST-API autorisiert werden. Wenn Sie die verifiable-credentials-app (Nachweise-App) noch nicht registriert haben, führen Sie die unter Registrieren der App beschriebenen Schritte aus und generieren Sie dann ein Anwendungsgeheimnis.
Zugriffstoken erhalten
Verwenden Sie den Flow zur Gewährung von OAuth 2.0-Clientanmeldeinformationen, um mithilfe von Microsoft Identity Platform das Zugriffstoken anzufordern. Verwenden Sie zu diesem Zweck eine vertrauenswürdige Bibliothek. In diesem Lernprogramm verwenden wir die Microsoft-Authentifizierungsbibliothek (MSAL). MSAL vereinfacht das Hinzufügen von Authentifizierung und Autorisierung zu einer App, die eine sichere Web-API aufrufen kann.
POST /{tenant}/oauth2/v2.0/token HTTP/1.1 //Line breaks for clarity
Host: login.microsoftonline.com
Content-Type: application/x-www-form-urlencoded
client_id=00001111-aaaa-2222-bbbb-3333cccc4444
&scope=3db474b9-6a0c-4840-96ac-1fceb342124f/.default
&client_secret=sampleCredentia1s
&grant_type=client_credentials
// Initialize MSAL library by using the following code
ConfidentialClientApplicationBuilder.Create(AppSettings.ClientId)
.WithClientSecret(AppSettings.ClientSecret)
.WithAuthority(new Uri(AppSettings.Authority))
.Build();
// Acquire an access token
result = await app.AcquireTokenForClient(AppSettings.Scopes)
.ExecuteAsync();
// Initialize MSAL library by using the following code
const msalConfig = {
auth: {
clientId: config.azClientId,
authority: `https://login.microsoftonline.com/${config.azTenantId}`,
clientSecret: config.azClientSecret,
},
system: {
loggerOptions: {
loggerCallback(loglevel, message, containsPii) {
console.log(message);
},
piiLoggingEnabled: false,
logLevel: msal.LogLevel.Verbose,
}
}
};
const cca = new msal.ConfidentialClientApplication(msalConfig);
const msalClientCredentialRequest = {
scopes: ["3db474b9-6a0c-4840-96ac-1fceb342124f/.default"],
skipCache: false,
};
module.exports.msalCca = cca;
module.exports.msalClientCredentialRequest = msalClientCredentialRequest;
// Acquire an access token
const result = await mainApp.msalCca.acquireTokenByClientCredential(mainApp.msalClientCredentialRequest);
if ( result ) {
accessToken = result.accessToken;
}
# Initialize MSAL library by using the following code
msalCca = msal.ConfidentialClientApplication( config["azClientId"],
authority="https://login.microsoftonline.com/" + config["azTenantId"],
client_credential=config["azClientSecret"],
)
# Acquire an access token
accessToken = ""
result = msalCca.acquire_token_for_client( scopes="3db474b9-6a0c-4840-96ac-1fceb342124f/.default" )
if "access_token" in result:
accessToken = result['access_token']
// Initialize MSAL library by using the following code
ConfidentialClientApplication app = ConfidentialClientApplication.builder(
clientId,
ClientCredentialFactory.createFromSecret(clientSecret))
.authority(authority)
.build();
// Acquire an access token
ClientCredentialParameters clientCredentialParam = ClientCredentialParameters.builder(
Collections.singleton(scope))
.build();
CompletableFuture<IAuthenticationResult> future = app.acquireToken(clientCredentialParam);
IAuthenticationResult result = future.get();
return result.accessToken();
Geben Sie im vorherigen Code die folgenden Parameter an:
Parameter |
Zustand |
Beschreibung |
Autorität |
Erforderlich |
Der Verzeichnismandant, der von der Anwendung für den Betrieb verwendet werden soll. Beispiel: https://login.microsoftonline.com/{your-tenant} . (Ersetzen Sie your-tenant mit Ihrer Mandanten-ID oder Ihrem Namen.) |
Kunden-ID |
Erforderlich |
Die Anwendungs-ID, die Ihrer App zugewiesen ist. Sie finden diese Informationen im Azure-Portal, in dem Sie Ihre App registriert haben. |
Geheimer Clientschlüssel |
Erforderlich |
Der geheime Clientschlüssel, den Sie für Ihre App generiert haben. |
Bereiche |
Erforderlich |
Muss auf 3db474b9-6a0c-4840-96ac-1fceb342124f/.default festgelegt sein. Diese Einstellung erstellt ein Zugriffstoken mit einem Rollenanspruch auf VerifiableCredential.Create.All . |
Weitere Informationen zum Abrufen eines Zugriffstokens mithilfe der Identität einer Konsolen-App finden Sie in einem der folgenden Artikel:
Sie können auch auf eine Tokenanforderung mit einem Zertifikat anstelle eines geheimen Clientschlüssels zugreifen.
POST /{tenant}/oauth2/v2.0/token HTTP/1.1 //Line breaks for clarity
Host: login.microsoftonline.com
Content-Type: application/x-www-form-urlencoded
client_id=00001111-aaaa-2222-bbbb-3333cccc4444
&scope=3db474b9-6a0c-4840-96ac-1fceb342124f/.default
&client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwt-bearer
&client_assertion=eyJhbGciOiJSUzI1NiIsIng1dCI6Imd4OHRHeXN5amNScUtqRlBuZDdSRnd2d1pJMCJ9.eyJ{a lot of characters here}M8U3bSUKKJDEg
&grant_type=client_credentials
// Initialize MSAL library by using the following code
X509Certificate2 certificate = AppSettings.ReadCertificate(AppSettings.CertificateName);
app = ConfidentialClientApplicationBuilder.Create(AppSettings.ClientId)
.WithCertificate(certificate)
.WithAuthority(new Uri(AppSettings.Authority))
.Build();
// Acquire an access token
result = await app.AcquireTokenForClient(AppSettings.Scopes)
.ExecuteAsync();
// Initialize MSAL library by using the following code
const msalConfig = {
auth: {
clientId: config.azClientId,
authority: `https://login.microsoftonline.com/${config.azTenantId}`,
clientCertificate: {
thumbprint: "CERT_THUMBPRINT", // a 40-digit hexadecimal string
privateKey: "CERT_PRIVATE_KEY"
}
},
system: {
loggerOptions: {
loggerCallback(loglevel, message, containsPii) {
console.log(message);
},
piiLoggingEnabled: false,
logLevel: msal.LogLevel.Verbose,
}
}
};
const cca = new msal.ConfidentialClientApplication(msalConfig);
const msalClientCredentialRequest = {
scopes: ["3db474b9-6a0c-4840-96ac-1fceb342124f/.default"],
skipCache: false,
};
module.exports.msalCca = cca;
module.exports.msalClientCredentialRequest = msalClientCredentialRequest;
// Acquire an access token
const result = await mainApp.msalCca.acquireTokenByClientCredential(mainApp.msalClientCredentialRequest);
if ( result ) {
accessToken = result.accessToken;
}
# Initialize MSAL library by using the following code
with open(config["azCertificatePrivateKeyLocation"], "rb") as file:
private_key = file.read()
with open(config["azCertificateLocation"]) as file:
public_certificate = file.read()
cert = load_pem_x509_certificate(data=bytes(public_certificate, 'UTF-8'), backend=default_backend())
thumbprint = (cert.fingerprint(hashes.SHA1()).hex())
msalCca = msal.ConfidentialClientApplication( config["azClientId"],
authority="https://login.microsoftonline.com/" + config["azTenantId"],
client_credential={
"private_key": private_key,
"thumbprint": thumbprint,
"public_certificate": public_certificate
}
)
# Acquire an access token
accessToken = ""
result = msalCca.acquire_token_for_client( scopes="3db474b9-6a0c-4840-96ac-1fceb342124f/.default" )
if "access_token" in result:
accessToken = result['access_token']
// Initialize MSAL library by using the following code
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(Files.readAllBytes(Paths.get(certKeyLocation)));
PrivateKey key = KeyFactory.getInstance("RSA").generatePrivate(spec);
java.io.InputStream certStream = (java.io.InputStream)new ByteArrayInputStream(Files.readAllBytes(Paths.get(certLocation)));
X509Certificate cert = (X509Certificate) CertificateFactory.getInstance("X.509").generateCertificate(certStream);
ConfidentialClientApplication app = ConfidentialClientApplication.builder(
clientId,
ClientCredentialFactory.createFromCertificate(key, cert))
.authority(authority)
.build();
// Acquire an access token
ClientCredentialParameters clientCredentialParam = ClientCredentialParameters.builder(
Collections.singleton(scope))
.build();
CompletableFuture<IAuthenticationResult> future = app.acquireToken(clientCredentialParam);
IAuthenticationResult result = future.get();
return result.accessToken();
Aufrufen der API
So stellen Sie einen verifizierbaren Berechtigungsnachweis aus oder überprüfen ihn:
Erstellen Sie eine HTTP POST-Anforderung an die REST-API des Anforderungsdiensts. Die Mandanten-ID wird in der URL nicht mehr benötigt, da sie im Zugriffstoken als Anspruch vorhanden ist.
Problem
POST https://verifiedid.did.msidentity.com/v1.0/verifiableCredentials/createIssuanceRequest
Überprüfen
POST https://verifiedid.did.msidentity.com/v1.0/verifiableCredentials/createPresentationRequest
Fügen Sie das Zugriffstoken als Bearer-Token an den Autorisierungsheader in einer HTTP-Anforderung an.
Authorization: Bearer <token>
Legen Sie den Header Content-Type
auf Application/json
fest.
Bereiten Sie die Ausstellungs- oder Präsentations-Anforderungsnutzdaten vor, und fügen Sie sie an den Anforderungstext an.
Übermitteln Sie die Anfrage an die REST-API des Anfragedienstes.
Die Anforderungsdienst-API gibt einen HTTP-Statuscode 201 Created
für einen erfolgreichen Aufruf zurück. Wenn der API-Aufruf einen Fehler zurückgibt, überprüfen Sie die Fehlerreferenzdokumentation.
Beispiel für eine Ausstellungsanforderung
Im folgenden Beispiel wird eine Anforderung zur Nachweisausstellung veranschaulicht. Informationen zu den Nutzdaten finden Sie unter Spezifikation der Ausstellung für die Anforderungsdienst-REST-API.
POST https://verifiedid.did.msidentity.com/v1.0/verifiableCredentials/createIssuanceRequest
Content-Type: application/json
Authorization: Bearer <token>
{...JSON payload...}
Ausstellungsanforderung mithilfe des Nachweisflusses idTokenHint
:
{
"authority": "did:web:verifiedid.contoso.com",
"callback": {
"url": "https://contoso.com/api/issuer/issuanceCallback",
"state": "de19cb6b-36c1-45fe-9409-909a51292a9c",
"headers": {
"api-key": "OPTIONAL API-KEY for CALLBACK EVENTS"
}
},
"registration": {
"clientName": "Verifiable Credential Expert Sample"
},
"type": "VerifiedCredentialExpert",
"manifestUrl": "https://verifiedid.did.msidentity.com/v1.0/00001111-aaaa-2222-bbbb-3333cccc4444/verifiableCredentials/contracts/VerifiedCredentialExpert1",
"pin": {
"value": "3539",
"length": 4
},
"claims": {
"given_name": "Megan",
"family_name": "Bowen"
}
}
Ausstellungsanforderung mithilfe des Nachweisflusses idTokenHint
, der das Ablaufdatum festlegt:
{
"authority": "did:web:verifiedid.contoso.com",
"callback": {
"url": "https://contoso.com/api/issuer/issuanceCallback",
"state": "de19cb6b-36c1-45fe-9409-909a51292a9c",
"headers": {
"api-key": "OPTIONAL API-KEY for CALLBACK EVENTS"
}
},
"registration": {
"clientName": "Verifiable Credential Expert Sample"
},
"type": "VerifiedCredentialExpert",
"manifestUrl": "https://verifiedid.did.msidentity.com/v1.0/00001111-aaaa-2222-bbbb-3333cccc4444/verifiableCredentials/contracts/VerifiedCredentialExpert1",
"pin": {
"value": "3539",
"length": 4
},
"claims": {
"given_name": "Megan",
"family_name": "Bowen"
},
"expirationDate": "2024-12-31T23:59:59.000Z"
}
Den vollständigen Code finden Sie in einem der folgenden Codebeispiele:
Beispiel für eine Präsentationsanforderung
Im folgenden Beispiel wird eine Anforderung zur Nachweispräsentation veranschaulicht. Informationen zu den Nutzdaten finden Sie unter Spezifikation der Präsentation der Anforderungsdienst-REST-API.
POST https://verifiedid.did.msidentity.com/v1.0/verifiableCredentials/createPresentationRequest
Content-Type: application/json
Authorization: Bearer <token>
{...JSON payload...}
Präsentationsanforderung für Anmeldeinformationen mit einem bestimmtem Typ und Aussteller:
{
"authority": "did:web:verifiedid.contoso.com",
"callback": {
"url": "https://contoso.com/api/verifier/presentationCallback",
"state": "92d076dd-450a-4247-aa5b-d2e75a1a5d58",
"headers": {
"api-key": "OPTIONAL API-KEY for CALLBACK EVENTS"
}
},
"registration": {
"clientName": "Veritable Credential Expert Verifier"
},
"includeReceipt": true,
"requestedCredentials": [
{
"type": "VerifiedCredentialExpert",
"purpose": "So we can see that you a veritable credentials expert",
"acceptedIssuers": [
"did:web:verifiedid.contoso.com"
],
"configuration": {
"validation": {
"allowRevoked": true,
"validateLinkedDomain": true
}
}
}
]
}
Präsentationsanforderung mit Anspruchseinschränkungen:
{
"authority": "did:web:verifiedid.contoso.com",
"includeReceipt": false,
"registration": {
"clientName": "Contoso Job Application Center",
"purpose": "Provide proof of attended courses"
},
"callback": {
"url": "https://contoso.com/api/verifier/presentationCallback",
"state": "92d076dd-450a-4247-aa5b-d2e75a1a5d58",
"headers": {
"api-key": "OPTIONAL API-KEY for CALLBACK EVENTS"
}
},
"requestedCredentials": [
{
"type": "FabrikamCourseCertification",
"acceptedIssuers": [ "did:web:learn.fabrikam.com" ],
"constraints": [
{
"claimName": "courseCode",
"values": ["FC100", "FC110", "FC150"],
},
{
"claimName": "courseTitle",
"contains": "network",
}
],
"configuration": {
"validation": {
"allowRevoked": false,
"validateLinkedDomain": true
}
}
}
]
}
Präsentationsanforderung mit FaceCheck. Wenn Sie FaceCheck verwenden, muss includeReceipt
falsch sein, da der Beleg dann nicht unterstützt wird.
{
"authority": "did:web:verifiedid.contoso.com",
"includeReceipt": false,
"registration": {
"clientName": "Contoso Job Application Center",
"purpose": "Provide proof of attended courses"
},
"callback": {
"url": "https://contoso.com/api/verifier/presentationCallback",
"state": "92d076dd-450a-4247-aa5b-d2e75a1a5d58",
"headers": {
"api-key": "OPTIONAL API-KEY for CALLBACK EVENTS"
}
},
"requestedCredentials": [
{
"type": "VerifiedEmployee",
"acceptedIssuers": [ "did:web:learn.contoso.com" ],
"configuration": {
"validation": {
"allowRevoked": false,
"validateLinkedDomain": true,
"faceCheck": {
"sourcePhotoClaimName": "photo",
"matchConfidenceThreshold": 70
}
}
}
}
]
}
Den vollständigen Code finden Sie in einem der folgenden Codebeispiele:
Rückrufereignisse
Die Anforderungsnutzdaten enthalten den Ausstellungs- und Präsentations-Rückrufendpunkt. Der Endpunkt ist Teil Ihrer Webanwendung und sollte über das HTTPS-Protokoll öffentlich verfügbar sein. Die Anforderungsdienst-API ruft Ihren Endpunkt auf, um Ihre App über bestimmte Ereignisse zu informieren. Beispielsweise können solche Ereignisse sein, wenn ein Benutzer den QR-Code durchsucht, den Deep-Link zur Authentifikator-App verwendet oder den Präsentationsprozess beendet.
Im folgenden Diagramm werden der Aufruf ihrer App an die Anforderungsdienst-REST-API und die Rückrufe an Ihre Anwendung beschrieben.
Konfigurieren Sie Ihren Endpunkt so, dass eingehende HTTP POST-Anforderungen überwacht werden. Der folgende Codeausschnitt veranschaulicht, wie die Veröffentlichungsrückruf-HTTP-Anforderung behandelt wird und wie die Benutzeroberfläche entsprechend aktualisiert wird:
Nicht zutreffend. Wählen Sie eine der anderen Programmiersprachen aus.
[HttpPost]
public async Task<ActionResult> IssuanceCallback()
{
try
{
string content = new System.IO.StreamReader(this.Request.Body).ReadToEndAsync().Result;
_log.LogTrace("callback!: " + content);
JObject issuanceResponse = JObject.Parse(content);
// More code here
if (issuanceResponse["code"].ToString() == "request_retrieved")
{
var cacheData = new
{
status = "request_retrieved",
message = "QR Code is scanned. Waiting for issuance...",
};
_cache.Set(state, JsonConvert.SerializeObject(cacheData));
// More code here
}
}
Den vollständigen Code finden Sie im Ausstellungs- und Präsentations-Code im GitHub-Repository.
mainApp.app.post('/api/issuer/issuance-request-callback', parser, async (req, res) => {
var body = '';
req.on('data', function (data) {
body += data;
});
req.on('end', function () {
requestTrace( req );
console.log( body );
var issuanceResponse = JSON.parse(body.toString());
var message = null;
if ( issuanceResponse.code == "request_retrieved" ) {
message = "QR Code is scanned. Waiting for issuance to complete...";
}
if ( issuanceResponse.code == "issuance_successful" ) {
message = "Credential successfully issued";
}
if ( issuanceResponse.code == "issuance_error" ) {
message = issuanceResponse.error.message;
}
// More code here
res.send()
});
res.send()
})
@app.route("/api/issuer/issuance-request-callback", methods = ['POST'])
def issuanceRequestApiCallback():
if request.headers['api-key'] != apiKey:
return Response( jsonify({'error':'api-key wrong or missing'}), status=401, mimetype='application/json')
issuanceResponse = request.json
if issuanceResponse["code"] == "request_retrieved":
cacheData = {
"status": issuanceResponse["code"],
"message": "QR Code is scanned. Waiting for issuance to complete..."
}
cache.set( issuanceResponse["state"], json.dumps(cacheData) )
return ""
if issuanceResponse["code"] == "issuance_successful":
cacheData = {
"status": issuanceResponse["code"],
"message": "Credential successfully issued"
}
cache.set( issuanceResponse["state"], json.dumps(cacheData) )
return ""
if issuanceResponse["code"] == "issuance_error":
cacheData = {
"status": issuanceResponse["code"],
"message": issuanceResponse["error"]["message"]
}
cache.set( issuanceResponse["state"], json.dumps(cacheData) )
return ""
return ""
@RequestMapping(value = "/api/issuer/issue-request-callback", method = RequestMethod.POST, produces = "application/json", consumes = "application/json")
public ResponseEntity<String> issueRequestCallback( HttpServletRequest request
, @RequestHeader HttpHeaders headers
, @RequestBody String body ) {
ObjectMapper objectMapper = new ObjectMapper();
try {
if ( !request.getHeader("api-key").equals(apiKey) ) {
lgr.info( "api-key wrong or missing" );
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body( "api-key wrong or missing" );
}
JsonNode presentationResponse = objectMapper.readTree( body );
String code = presentationResponse.path("code").asText();
ObjectNode data = null;
if ( code.equals( "request_retrieved" ) ) {
data = objectMapper.createObjectNode();
data.put("message", "QR Code is scanned. Waiting for issuance to complete..." );
}
if ( code.equals("issuance_successful") ) {
data = objectMapper.createObjectNode();
data.put("message", "Credential successfully issued" );
}
if ( code.equals( "issuance_error" ) ) {
data = objectMapper.createObjectNode();
data.put("message", presentationResponse.path("error").path("message").asText() );
}
if ( data != null ) {
data.put("status", code );
cache.put( presentationResponse.path("state").asText(), objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(data) );
}
} catch (java.io.IOException ex) {
ex.printStackTrace();
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body( "Technical error" );
}
return ResponseEntity.ok().body( "{}" );
}
Den vollständigen Code finden Sie im Ausstellungs- und Präsentations-Code im GitHub-Repository.
Nächste Schritte
Weitere Informationen zu diesen Spezifikationen: