cookie-information / android-release

0 stars 2 forks source link

postConsent returns 401 invalid_token #5

Closed LasseMortensen closed 1 year ago

LasseMortensen commented 1 year ago

Hi

Issue postConsent returns 401 invalid_token Version: 0.2.7

Background I'm trying to implement a dialog where the user can choose to accept to all consent, all required or custom (opens your UI). The first two options require postConsent to be called but it returns 401 invalid_token. However fetchConsentSolution, shouldDisplayConsents and displayConsents works fine.

Implementation Post method:

private fun postUserConsent(
    hasConsentedToAll: Boolean,
    onComplete: ((didShowConsentDialog: Boolean) -> Unit)?
) {
    consentsSDK.fetchConsentSolution(object : CallListener<ConsentSolution> {
        override fun onSuccess(result: ConsentSolution) {
            val consent = createConsent(result, hasConsentedToAll)
            consentsSDK.postConsent(consent, object : CallListener<Unit> {
                override fun onSuccess(result: Unit) {
                    // Store consents in memory
                    setUserConsents(consent.processingPurposes.associate { it.type to it.consentGiven })
                    onComplete?.invoke(true)
                }

                override fun onFailure(e: IOException) {
                    e.printStackTrace()
                    onComplete?.invoke(true)
                }
            })
        }

        override fun onFailure(e: IOException) {
            e.printStackTrace()
            onComplete?.invoke(true)
        }
    })
}

createConsent method:

private fun createConsent(
    consentSolution: ConsentSolution,
    hasConsentedToAll: Boolean
): Consent {
    val purposes = consentSolution.consentItems.map { consentItem ->
        ProcessingPurpose(
            consentItemId = consentItem.consentItemId,
            consentGiven = consentItem.required || hasConsentedToAll,
            language = consentItem.shortText.first().languageCode,
            type = consentItem.type
        )
    }

    return Consent(
        consentSolutionId = consentSolution.consentSolutionId,
        consentSolutionVersionId = consentSolution.consentSolutionVersionId,
        processingPurposes = purposes,
        customData = emptyMap()
    )
}

Error log

FATAL EXCEPTION: main
Process: com.nemlig.test, PID: 6851
java.lang.IllegalStateException: 
Tag: UserConsentManager.
Message: Post error: java.io.IOException: Url: https://consent-api.app.cookieinformation.com/v1
Code: 401
Message: {"error_description":"The access token is invalid or has expired","error":"invalid_token"}.
    at com.nemlig.base.user.UserConsentManager$postUserConsent$1$onSuccess$1.onFailure(UserConsentManager.kt:143)
    at com.cookieinformation.mobileconsents.MobileConsents$postConsent$job$1.invokeSuspend(MobileConsents.kt:72)
    at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
    at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:104)
    at android.os.Handler.handleCallback(Handler.java:938)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:246)
    at android.app.ActivityThread.main(ActivityThread.java:8633)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:602)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1130)
    Suppressed: kotlinx.coroutines.DiagnosticCoroutineContextException: [StandaloneCoroutine{Cancelling}@d0ff1e1, Dispatchers.Main]
--> GET https://cdnapi-prod.azureedge.net/v1/[REDACTED]/consent-data.json
--> END GET
<-- 200 https://cdnapi-prod.azureedge.net/v1/[REDACTED]/consent-data.json (23ms)
access-control-allow-origin: *
access-control-expose-headers: x-ms-request-id,Server,x-ms-version,Content-Length,Date,Transfer-Encoding
age: 18
cache-control: max-age=300
content-md5: 6shM/59mf57JjHM7dTuBGA==
content-type: application/json
date: Tue, 07 Mar 2023 08:05:20 GMT
etag: 0x8DB1E2000BE35F4
expires: Tue, 07 Mar 2023 08:10:20 GMT
last-modified: Mon, 06 Mar 2023 08:51:40 GMT
server: ECAcc (frc/4CAC)
vary: Accept-Encoding
x-cache: HIT
x-ms-blob-type: BlockBlob
x-ms-lease-status: unlocked
x-ms-request-id: [REDACTED]
x-ms-version: 2009-09-19
x-robots-tag: noindex, noarchive, nosnippet
{"universalConsentSolutionVersionId":"[REDACTED]","universalConsentSolutionId":"[REDACTED]","universalConsentItems":[{"universalConsentItemId":"[REDACTED]","translations":[{"language":"DA","shortText":"Firebase crashlytics","longText":"Denne service indsamler fejlrapporter fra appen. Dette inkluderer nedbrud, men også andre fejl, som brugere muligvis ikke bemærker."}],"required":false,"type":"functional"},{"universalConsentItemId":"[REDACTED]","translations":[{"language":"DA","shortText":"Firebase Remote Config","longText":"Firebase Remote Config er en tjeneste, der muliggør ændringer i adfærd og udseende af en app uden at kræve, at en bruger downloader en app opdatering. Bruges også til at have dynamiske konfigurationer i appen (som forside og tekster)"}],"required":true,"type":"necessary"},{"universalConsentItemId":"[REDACTED]","translations":[{"language":"DA","shortText":"Firebase Performance Monitoring","longText":"Firebase performance Monitoring er en service, der bruges til at få indsigt i ydeevne egenskaber for nemlig.com apps. Denne information bruges til at forstå, hvor og hvornår ydelsen af appen kan forbedres og til at løse ydelsesproblemer. "}],"required":false,"type":"statistical"},{"universalConsentItemId":"[REDACTED]","translations":[{"language":"DA","shortText":"Firebase test short text","longText":"test of long text "}],"required":false,"type":"custom"},{"universalConsentItemId":"[REDACTED]","translations":[{"language":"DA","shortText":"Fortrolighedspolitik","longText":"Lang beskrivelse af fortrolighedspolitik"}],"required":true,"type":"privacy policy"}],"title":[],"description":[],"templateTexts":{"title":[{"language":"EN","text":"Privacy settings"},{"language":"FI","text":"Tietosuoja-asetukset"},{"language":"DA","text":"Privatlivsindstillinger"},{"language":"FR","text":"Paramètres de confidentialité"}],"acceptAllButton":[{"language":"FI","text":"Hyväksy kaikki"},{"language":"DA","text":"Accepter alle"},{"language":"FR","text":"Accepter tout"},{"language":"EN","text":"Accept all"}],"rejectAllButton":[{"language":"FI","text":"Hylkää kaikki"},{"language":"DA","text":"Afvis alle"},{"language":"FR","text":"Refuser tout"},{"language":"EN","text":"Reject all"}],"acceptSelectedButton":[{"language":"FI","text":"Hyväksy valitut"},{"language":"DA","text":"Accepter valgte"},{"language":"FR","text":"Accepter la sélection"},{"language":"EN","text":"Accept selected"}],"savePreferencesButton":[{"language":"FI","text":"Tallenna"},{"language":"DA","text":"Gem"},{"language":"FR","text":"Enregistrer"},{"language":"EN","text":"Accept"}],"privacyCenterTitle":[{"language":"FI","text":"Tietosuoja"},{"language":"DA","text":"Privatliv"},{"language":"FR","text":"Confidentialité"},{"language":"EN","text":"Privacy"}],"privacyPreferencesTabLabel":[{"language":"FI","text":"Tietosuoja-asetukset"},{"language":"DA","text":"Privatlivspræferencer"},{"language":"FR","text":"Préférences de confidentialité"},{"language":"EN","text":"Privacy preferences"}],"privacyCenterButton":[{"language":"FI","text":"Lue lisää"},{"language":"DA","text":"Læs mere"},{"language":"FR","text":"En savoir plus"},{"language":"EN","text":"Read more"}],"poweredByCoiLabel":[{"language":"FI","text":"Palvelun tarjoaa Cookie Information"},{"language":"DA","text":"Drevet af Cookie Information"},{"language":"FR","text":"Propulsé par les cookies"},{"language":"EN","text":"Powered by Cookie Information"}],"consentPreferencesLabel":[{"language":"FI","text":"Suostumusasetukset"},{"language":"DA","text":"Samtykkepræferencer"},{"language":"FR","text":"Préférences de consentement"},{"language":"EN","text":"consent preferences"}],"description":[{"language":"FI","text":"Joitakin käytetään tilastointitarkoituksiin ja toiset ovat kolmannen osapuolen palvelujen luomia. Klikkaamalla “Hyväksy kaikki” hyväksyt ev
ästeiden käytön."},{"language":"DA","text":"Nogle bruges til statistiske formål, og andre er oprettet af tredjepartstjenester. Ved at klikke på “Accepter alle”, accepterer du brugen af cookies."},{"language":"FR","text":"Certains sont utilisés à des fins statistiques alors que d'autres sont mis en place par des services tiers. En cliquant sur \"Accepter tout\", vous acceptez l'utilisation des cookies."},{"language":"EN","text":"Some are used for statistical purposes and others are set up by third party services. By Clicking “Accept all”, you accept the use of cookies."}]}}
<-- END HTTP (4633-byte body)
--> POST https://consent-api.app.cookieinformation.com/v1
Content-Length: 862
Authorization: Bearer null
Content-Type: application/json; charset=utf-8
{"userId":"[REDACTED]","universalConsentSolutionId":"[REDACTED]","universalConsentSolutionVersionId":"[REDACTED]","processingPurposes":[{"consentGiven":true,"language":"DA","universalConsentItemId":"[REDACTED]"},{"consentGiven":true,"language":"DA","universalConsentItemId":"[REDACTED]"},{"consentGiven":true,"language":"DA","universalConsentItemId":"[REDACTED]"},{"consentGiven":true,"language":"DA","universalConsentItemId":"[REDACTED]"},{"consentGiven":true,"language":"DA","universalConsentItemId":"[REDACTED]"}],"customData":[],"platformInformation":{"operatingSystem":"Android 11","applicationId":"com.nemlig.test","applicationName":"nemlig.test"}}
--> END POST (862-byte body)
<-- 401 https://consent-api.app.cookieinformation.com/v1 (189ms)
date: Tue, 07 Mar 2023 08:05:20 GMT
content-type: application/json; charset=utf-8
www-authenticate: Bearer realm="service" error="invalid_token" error_description="The access token is invalid or has expired"
content-length: 90
x-kong-response-latency: 0
server: kong/3.1.1
{"error_description":"The access token is invalid or has expired","error":"invalid_token"}
<-- END HTTP (90-byte body)
LasseMortensen commented 1 year ago

It seems to be an issue where the token is null as it have not yet been saved in preferences. It looks like it will only be saved in the view model but we will not call displayConsents if the user accepts all or necessary consents in our dialog

HannahShulman commented 1 year ago

Hello! Yes, you are right. A valid token for your consent has not been requested. I will be adding a verification for a valid token prior to posting the consent.

LasseMortensen commented 1 year ago

Version 1.0.4 seems to fix the issue, thanks ✅