Build your rQES Core for Android
The EUDI rQES Core SDK provides the foundational service logic for enabling Remote Qualified Electronic Signatures (RQES) in Android applications. This document explains how to integrate and use the Core SDK in your project.
Overview
This SDK provides the core functionality for an EUDI Wallet to interact with a remote Qualified Electronic Signature (rQES) service. It handles service authorisation, credential authorisation, and document signing.
Requirements
Android 10 (API level 29) or higher
Installation
To include the library in your project, add the following dependencies to your app's build.gradle file.
dependencies {
// EUDI Wallet rQES service library
implementation("eu.europa.ec.eudi:eudi-lib-android-rqes-core:0.4.0")
}
Integration guide
The following diagram illustrates the high-level steps of the rQES document signing flow, from service authorisation to obtaining the final signed documents.
sequenceDiagram
participant Client
participant rQESService
participant rQESService.Authorized
participant rQESService.CredentialAuthorized
Client ->>+ rQESService: getRSSPMetadata()
rQESService -->>- Client: RSSPMetadata
Client ->>+ rQESService: getServiceAuthorizationUrl()
rQESService -->>- Client: HttpsUrl
Client ->>+ rQESService: authorizeService(authorizationCode)
rQESService -->>- Client: RQESService.Authorized
Client ->>+ rQESService.Authorized: listCredentials(request)
rQESService.Authorized -->>- Client: List<CredentialInfo>
Client ->>+ rQESService.Authorized: getCredentialAuthorizationUrl(credential, UnsignedDocuments)
rQESService.Authorized -->>- Client: HttpsUrl
Client ->>+ rQESService.Authorized: authorizeCredential(authorizationCode)
rQESService.Authorized -->>- Client: RQESService.CredentialAuthorized
Client ->>+ rQESService.CredentialAuthorized: signDocuments()
rQESService.CredentialAuthorized -->>- Client: SignedDocuments
1. Create an rQESService instance
val rqesService = rQESService(
serviceEndpointUrl = "https://example.com/csc/v2",
config = CSCClientConfig(
client = OAuth2Client.Confidential.ClientSecretBasic(
clientId = "client-id",
clientSecret = "client-secret"
),
authFlowRedirectionURI = URI("rqes:redirect"),
),
outputPathDir = "/path/to/output/dir",
// set the hashing algorithm that will be used
// default is SHA-256 as shown below
hashAlgorithm = HashAlgorithmOID.SHA_256,
// optionally provide a HttpClientFactory to create a HttpClient for the service
// this is useful for logging, testing, etc.
httpClientFactory = {
// create a HttpClient
HttpClient(/* Configure */)
}
)
You can fetch the rQES service metadata:
val metadata = rqesService.getRSSPMetadata().getOrThrow()
2. Authorise the rQES service
To begin the signing process, the user must authorise your application to use the rQES service.
First, obtain the service authorisation URL and open it in a custom tab or browser:
val authorizationUrl = rqesService.getServiceAuthorizationUrl().getOrThrow()
// Open the authorizationUrl in a browser
// After the user has authorised the service, the browser will be redirected to the authFlowRedirectionURI that
// is configured in the `CSCClientConfig`
// with a query parameter named "code" containing the authorisation code
After the user grants authorisation, the service will redirect to the authFlowRedirectionURI you configured, appending an authorisation code as a query parameter. Your app must capture this redirect, extract the code, and exchange it for an access token.
val authorizationCode = AuthorizationCode("code")
val authorizedService = rqesService.authorizeService(authorizationCode).getOrThrow()
3. Select a credential and prepare documents
Once the service is authorised, you can list the user's available signing credentials.
val credentials = authorizedService.listCredentials().getOrThrow()
val credential = credentials.first() // choose whichever credential you want
Next, prepare the documents that need to be signed.
val unsignedDocuments = UnsignedDocuments(
UnsignedDocument(
label = "Document to sign",
file = File("document.pdf"),
// Optionally override default signing configuration
signingConfig = UnsignedDocument.Config(
signatureFormat = SignatureFormat.P,
conformanceLevel = ConformanceLevel.ADES_B_B,
signedEnvelopeProperty = SignedEnvelopeProperty.ENVELOPED,
asicContainer = ASICContainer.NONE
)
)
)
4. Authorise the credential and sign
The user must now authorise the use of their selected credential for this specific transaction.
Obtain the credential authorizationURL to open a browser and let the user authorise the credential.
val credentialAuthorizationUrl = authorizedService.getCredentialAuthorizationUrl(
credential = credential,
documents = unsignedDocuments,
// Optional: signing algorithm. If omitted, the first supported algorithm of the credential is used.
signingAlgorithmOID = SigningAlgorithmOID.ECDSA_SHA256
).getOrThrow()
// Open credentialAuthorizationUrl in a browser.
// After authorisation, the browser will redirect to authFlowRedirectionURI
// with a query parameter "code" containing the credential authorisation code.
Similar to service authorisation, the user will be redirected back to your authFlowRedirectionURI with a new code.
Use this code to complete the signing process:
val credentialAuthorizationCode = AuthorizationCode("credential-code")
val authorizedCredential =
authorizedService.authorizeCredential(credentialAuthorizationCode).getOrThrow()
val signedDocuments = authorizedCredential.signDocuments().getOrThrow()
// Manipulate the signed documents
signedDocuments.forEach { (label, file) ->
// Use the signed file
val fileContent = file.readBytes()
}
You can also sign without explicitly calling authorizeCredential:
val signedDocumentsAlt = authorizedService.signDocuments(credentialAuthorizationCode).getOrThrow()
Source code
The source code is available on GitHub: eudi-lib-android-rqes-core.