Certificate authentication - Rest PKI Core
Users can sign in to your application with their digital certificate. Rest PKI Core does the backend part of the certificate authentication process, and Web PKI the part that runs in the browser:
- Your server asks Rest PKI Core to prepare an authentication. Rest PKI Core generates a random nonce and returns the hash to sign and the authentication state.
- On your page, the user chooses a certificate, and Web PKI signs the hash with it. The page sends the certificate's encoding, the signature and the state to your server.
- Your server sends them to Rest PKI Core, which completes the authentication: it checks the signature, validates the certificate and checks that the nonce was not used before.
- If the authentication succeeds, your application finds the user by a field of the certificate, such as the CPF or the email address, and signs them in.
From this point on we'll describe calls to Rest PKI Core. Make sure you've read the Get Started article to be able to keep up. The application's API key needs a role that allows certificate authentication, such as Worker (see Choosing roles). Outside of localhost, Web PKI needs a license.
Preparing the authentication
On .NET, call IRestPkiService.PrepareAuthenticationAsync():
var prepareAuthResult = await restPkiService.PrepareAuthenticationAsync(securityContextId: securityContextId);
// Pass these to the page
var state = prepareAuthResult.State;
var toSignHash = Convert.ToBase64String(prepareAuthResult.ToSign.Hash);
var digestAlgorithm = prepareAuthResult.ToSign.SignatureAlgorithm.DigestAlgorithm.Oid;
securityContextIddecides which certificates are trusted. If omitted, Rest PKI Core uses the subscription's default security context or, without one, the instance's.ignoreRevocationStatusUnknownaccepts certificates whose revocation status cannot be determined. If omitted, the subscription's setting applies or, without one, the instance's.
The result has the hash to sign in ToSign.Hash, its digest algorithm in ToSign.SignatureAlgorithm.DigestAlgorithm, and the state in State, an
opaque string that Rest PKI Core needs to complete the authentication. Preparing stores nothing on Rest PKI Core, so you can prepare an authentication
every time your login page is shown.
On Java, call RestPkiService.prepareAuthentication():
PrepareAuthenticationOptions options = new PrepareAuthenticationOptions();
options.setSecurityContext(SecurityContext.pkiBrazil);
PrepareAuthenticationResult prepareAuthResult = restPkiService.prepareAuthentication(options);
// Pass these to the page
String state = prepareAuthResult.getState();
String toSignHash = prepareAuthResult.getToSignHash().getValueAsBase64();
String digestAlgorithm = prepareAuthResult.getToSignHash().getAlgorithm().getName();
If calling the API directly, do:
POST {endpoint}/api/v2/authentication
{
"securityContextId": "...",
"ignoreRevocationStatusUnknown": false
}
The response has the hash to sign in toSign.hash (Base64), its digest algorithm in toSign.signatureAlgorithm.digestAlgorithmOid, and the state in
state. It also repeats the hash in toSignHash, for older clients.
Signing the hash on your page
The user's certificate never leaves their computer, so Web PKI signs the hash in the browser:
- List the user's certificates with Web PKI's
listCertificates(). - When the user chooses one, read its encoding with
readCertificate()and sign the hash withsignHash(). - Send the certificate's encoding and the signature, both in Base64, and the state to your server, which completes the authentication.
pki.readCertificate({ thumbprint: thumbprint }).success(function (certificate) {
pki.signHash({
thumbprint: thumbprint, // the certificate chosen by the user
hash: toSignHash, // the hash to sign, in Base64
digestAlgorithm: digestAlgorithm // the digest algorithm, as given by your server
}).success(function (signature) {
// Send the certificate, the signature (both in Base64) and the state to your server
});
});
The state is protected by Rest PKI Core, so you can keep it in a hidden field of the page. For listCertificates(), readCertificate() and
signHash(), see Web PKI's Get started.
Completing the authentication
On .NET, call IRestPkiService.CompleteAuthenticationAsync() with the state, the certificate and the signature:
var authResult = await restPkiService.CompleteAuthenticationAsync(
state,
Convert.FromBase64String(certificate),
Convert.FromBase64String(signature)
);
if (authResult.Success) {
var userCert = authResult.Certificate;
// Find the user by a field of the certificate, such as userCert.PkiBrazil.Cpf or userCert.EmailAddress, and sign them in
} else {
// authResult.Failure says why
}
When Success is false, Failure says why:
Failure | What happened | What to do |
|---|---|---|
CertificateFailedValidation | The certificate is not valid under the security context, for instance it is revoked or not trusted | Show the reasons, in ValidationResults |
StaleSession | The authentication expired before it was completed: by default, an authentication lasts 60 minutes | Prepare a new authentication |
NonceReused | The state was already used to complete an authentication, which can mean a replay attack | Prepare a new authentication |
If the signature doesn't match the hash, usually an error on your page, Rest PKI Core answers with HTTP 422 and the error code BadSignature instead
(see Errors).
On Java, call RestPkiService.completeAuthentication():
CompleteAuthenticationOptions request = new CompleteAuthenticationOptions();
request.setCertificateFromBase64(certificate);
request.setSignatureFromBase64(signature);
request.setState(state);
AuthenticationResult authResult = restPkiService.completeAuthentication(request);
if (authResult.isSuccess()) {
// authResult.getCertificate() is the user's certificate
} else if (authResult.getFailure().equals(AuthenticationFailures.CERTIFICATEFAILEDVALIDATION)) {
// authResult.getValidationResults() says why the certificate was rejected
} else {
// Prepare a new authentication
}
If calling the API directly, do:
POST {endpoint}/api/v2/authentication/completion
{
"state": "...",
"certificate": "Base64EncodedCertificate==",
"signature": "Base64EncodedSignature=="
}
The response has success, failure, the user's certificate in certificate and, when the certificate was validated, the results in
validationResults.
Rest PKI Core also serves the authentication API of the classic Rest PKI (Api/Authentications),
which eases moving an application that authenticates with Rest PKI to Rest PKI Core. See
Moving from Rest PKI to Rest PKI Core.