El Identificador Verificado de Microsoft Entra incluye la API REST del Servicio de Solicitudes. Esta API le permite emitir y comprobar las credenciales. En este artículo se muestra cómo empezar a usar la API REST del servicio de solicitud.
Token de acceso de API
La aplicación debe incluir un token de acceso válido con los permisos necesarios para que pueda acceder a la API rest del servicio de solicitudes. Los tokens de acceso emitidos por la plataforma de identidad de Microsoft contienen información (ámbitos) que usa la API rest del servicio de solicitud para validar al autor de la llamada. Un token de acceso garantiza que el autor de la llamada tenga los permisos adecuados para realizar la operación que solicitan.
Para obtener un token de acceso, la aplicación debe registrarse en la plataforma de identidad de Microsoft y ser autorizada por un administrador para acceder a la API rest del servicio de solicitud. Si no ha registrado la aplicación verifiable-credentials-app, consulte cómo registrar la aplicación y luego genere un secreto de aplicación.
Obtención de un token de acceso
Use el flujo de concesión de credenciales de cliente de OAuth 2.0 para adquirir el token de acceso usando la plataforma de identidad de Microsoft. Use una biblioteca de confianza para este propósito. En este tutorial, usamos la biblioteca de autenticación de Microsoft (MSAL). MSAL simplifica la adición de autenticación y autorización a una aplicación que puede llamar a una API web segura.
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();
En el código anterior, proporcione los parámetros siguientes:
Parámetro
Condición
Descripción
Autoridad
Obligatorio
Inquilino del directorio en el que la aplicación tiene previsto funcionar. Por ejemplo: https://login.microsoftonline.com/{your-tenant}. (Remplace your-tenant por el identificador o nombre de inquilino).
Id. de cliente
Obligatorio
Identificador de aplicación asignado a la aplicación. Puede encontrar esta información en Azure Portal, donde registró la aplicación.
Secreto de cliente
Obligatorio
El secreto de cliente que generaste para tu aplicación.
Ámbitos
Obligatorio
Debe establecerse en 3db474b9-6a0c-4840-96ac-1fceb342124f/.default. Este ajuste genera un token de acceso con una notificación roles con el valor VerifiableCredential.Create.All.
Para obtener más información sobre cómo obtener un token de acceso mediante la identidad de una aplicación de consola, consulte uno de los siguientes artículos:
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();
Llamada a la API
Para emitir o comprobar una credencial verificable:
Construya una solicitud HTTP POST a la API REST del servicio de solicitud. El identificador de inquilino ya no es necesario en la dirección URL porque está presente como una notificación en el token de acceso.
Problema
POST https://verifiedid.did.msidentity.com/v1.0/verifiableCredentials/createIssuanceRequest
Verify
POST https://verifiedid.did.msidentity.com/v1.0/verifiableCredentials/createPresentationRequest
Adjunte el token de acceso como token de portador al encabezado de autorización en una solicitud HTTP.
Authorization: Bearer <token>
Establezca el encabezado Content-Type en Application/json.
Prepare y adjunte la carga de la solicitud de emisión o presentación al cuerpo de la solicitud.
Envíe la solicitud a la API REST del servicio de solicitudes.
Request Service API devuelve un código de estado HTTP 201 Created en una llamada correcta. Si la llamada API devuelve un error, compruebe la documentación de referencia de error .
La carga de la solicitud contiene el punto de conexión de devolución de llamada de emisión y de presentación. El punto de conexión forma parte de la aplicación web y debe estar disponible públicamente a través del protocolo HTTPS. Request Service API llama al punto de conexión para informar a la aplicación de determinados eventos. Por ejemplo, estos eventos pueden ser cuando un usuario examina el código QR, usa el vínculo profundo a la aplicación autenticadora o finaliza el proceso de presentación.
En el siguiente diagrama se describen la llamada que realiza su aplicación a la API REST de servicios de solicitud y las devoluciones de llamada a la aplicación.
Configure el punto de conexión para escuchar las solicitudes HTTP POST entrantes. En el siguiente fragmento de código se muestra cómo controlar la solicitud HTTP de devolución de llamada de emisión y cómo actualizar la interfaz de usuario en consecuencia:
No aplicable. Elija uno de los otros lenguajes de programación.
[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
}
}
Para obtener el código completo, consulte el código de emisión y el código de presentación en el repositorio de GitHub.
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()
})