Acapadev

Integração Avançada

Aplicações Mobile & PKCE

Ao desenvolver aplicações móveis nativas (Android, iOS) ou Single Page Applications (SPAs) puras, o paradigma de segurança do OAuth2 muda radicalmente. Ao contrário de um servidor backend fechado (como PHP ou Node.js), um APK Android ou um binário iOS não consegue armazenar o `Client Secret` em segurança. Se o embutir no código, qualquer atacante pode descompilar a app e roubá-lo.

Para resolver isto, o Acapadev ID suporta nativamente a arquitetura PKCE (Proof Key for Code Exchange). No fluxo PKCE, o Client Secret não existe. Em vez disso, a sua App gera chaves temporárias criptográficas a cada nova tentativa de login.


Como funciona o PKCE no Acapadev ID?

Todo o processo é transparente se usar bibliotecas modernas como o AppAuth (Android/iOS). A lógica base é:

  1. A sua App Mobile gera uma string aleatória chamada Code Verifier.
  2. A App aplica um algoritmo criptográfico (SHA-256) a esse verifier para criar o Code Challenge.
  3. O utilizador clica em "Login" e a App abre o navegador do telemóvel na página de Login do Acapadev ID, enviando o Code Challenge no URL.
  4. O Acapadev guarda o Challenge e devolve o Authorization Code.
  5. A sua app intercepta o redirecionamento (via Deep Link), e envia o Code Verifier original (não encriptado) diretamente para o Acapadev ID pedir o Token final.
  6. O Acapadev ID verifica se o Verifier bate certo com o Challenge inicial e, se sim, entrega o Access Token!

Passo 1: Criar a App no Portal

No seu Dashboard de Developer, ao criar uma nova aplicação, certifique-se de selecionar o tipo Native.

O Segredo está na URL de Redirecionamento

Em vez de usar https://..., a sua URL de redirecionamento (Redirect URI) deve ser um Custom URI Scheme que pertence apenas à sua app (Deep Link), para que o Sistema Operativo do telemóvel saiba que deve abrir a sua aplicação após o login. Exemplo: com.suaempresa.app://callback.


Passo 2: Implementação em Android

Recomendamos vivamente o uso da biblioteca oficial AppAuth for Android, pois implementa o PKCE automaticamente.

1. Dependências e AndroidManifest.xml

Adicione no seu build.gradle e configure o schema do Redirect URI para que o Android intercepte o link de retorno:


<!-- No AndroidManifest.xml, dentro da atividade RedirectUriReceiverActivity -->
<intent-filter>
    <action android:name="android.intent.action.VIEW"/>
    <category android:name="android.intent.category.DEFAULT"/>
    <category android:name="android.intent.category.BROWSABLE"/>
    <!-- Deve ser idêntico ao que colocou no Portal Acapadev -->
    <data android:scheme="com.suaempresa.app" android:host="callback"/>
</intent-filter>

2. Iniciar o Fluxo OAuth2 PKCE (Kotlin)

A biblioteca trata de criar o Challenge e o Verifier nos bastidores. Basta iniciar o intent:


val serviceConfiguration = AuthorizationServiceConfiguration(
    Uri.parse("https://id.acapadev.com/oauth/authorize"), // Authorization Endpoint
    Uri.parse("https://id.acapadev.com/oauth/token")      // Token Endpoint
)

val clientId = "O_SEU_CLIENT_ID" // Retire do Portal Acapadev
val redirectUri = Uri.parse("com.suaempresa.app://callback")

val authRequestBuilder = AuthorizationRequest.Builder(
    serviceConfiguration,
    clientId,
    ResponseTypeValues.CODE,
    redirectUri
)

val authRequest = authRequestBuilder.build()
val authService = AuthorizationService(this)

// O próprio SDK do Android cria o PKCE Challenge e abre o Chrome Custom Tabs
val authIntent = authService.getAuthorizationRequestIntent(authRequest)
startActivityForResult(authIntent, RC_AUTH)

3. Trocar o Código pelo Token

Após o utilizador fazer login, o seu telemóvel volta à sua App Android. Agora, use a biblioteca para trocar o código (com o PKCE Verifier) pelo Access Token final:


override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
    if (requestCode == RC_AUTH) {
        val resp = AuthorizationResponse.fromIntent(data!!)
        val ex = AuthorizationException.fromIntent(data)

        if (resp != null) {
            // Sucesso! Vamos pedir o Token ao Acapadev ID
            val authService = AuthorizationService(this)
            
            // O AppAuth inclui o client_secret (PKCE Verifier) automaticamente
            authService.performTokenRequest(resp.createTokenExchangeRequest()) { tokenResponse, exception ->
                if (tokenResponse != null) {
                    val accessToken = tokenResponse.accessToken
                    Log.d("Acapadev", "Token Recebido: $accessToken")
                    // Login concluído com sucesso! Use o accessToken para pedir os dados do utilizador
                }
            }
        }
    }
}

iOS e Swift?

A implementação no iOS segue exatamente a mesma lógica usando a biblioteca AppAuth for iOS. Registe a sua URL Scheme no Info.plist e siga a mesma estrutura de OIDAuthorizationService.

Enter para selecionar ESC para sair