{"action":"created","issue":{"url":"https://api.github.com/repos/GoogleCloudPlatform/community/issues/572","repository_url":"https://api.github.com/repos/GoogleCloudPlatform/community","labels_url":"https://api.github.com/repos/GoogleCloudPlatform/community/issues/572/labels{/name}","comments_url":"https://api.github.com/repos/GoogleCloudPlatform/community/issues/572/comments","events_url":"https://api.github.com/repos/GoogleCloudPlatform/community/issues/572/events","html_url":"https://github.com/GoogleCloudPlatform/community/issues/572","id":372398600,"node_id":"MDU6SXNzdWUzNzIzOTg2MDA=","number":572,"title":"Firebase Auth Not Working With Ktor App On AppEngine","user":{"login":"AdamSHurwitz","id":3938076,"node_id":"MDQ6VXNlcjM5MzgwNzY=","avatar_url":"https://avatars0.githubusercontent.com/u/3938076?v=4","gravatar_id":"","url":"https://api.github.com/users/AdamSHurwitz","html_url":"https://github.com/AdamSHurwitz","followers_url":"https://api.github.com/users/AdamSHurwitz/followers","following_url":"https://api.github.com/users/AdamSHurwitz/following{/other_user}","gists_url":"https://api.github.com/users/AdamSHurwitz/gists{/gist_id}","starred_url":"https://api.github.com/users/AdamSHurwitz/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/AdamSHurwitz/subscriptions","organizations_url":"https://api.github.com/users/AdamSHurwitz/orgs","repos_url":"https://api.github.com/users/AdamSHurwitz/repos","events_url":"https://api.github.com/users/AdamSHurwitz/events{/privacy}","received_events_url":"https://api.github.com/users/AdamSHurwitz/received_events","type":"User","site_admin":false},"labels":[],"state":"closed","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":0,"created_at":"2018-10-22T05:29:03Z","updated_at":"2019-01-02T22:38:51Z","closed_at":"2019-01-02T22:38:51Z","author_association":"NONE","body":"# Issue\r\n\r\nWhen deploying a **Ktor** Kotlin application to AppEngine per the [Ktor tutorial](https://cloud.google.com/community/tutorials/kotlin-ktor-app-engine-java8), the Firestore server authentication is not working, thus data is not being written to the specified Firestore database. \r\n\r\nData is written as expected to Firestore both when the app is run directly in the IntelliJ IDE as well as when it is run with **ktor**'s implementation via the `gradle appengineRun` command.\r\n\r\nThere are two sets of AppEngine/Firebase projects for both a *staging* and *production* environment. Prior to deploying with the `gradle appengineDeploy` command the correct SDK configuration been activated and verified via the command `gcloud config configurations list.`\r\n\r\n[![enter image description here][1]][1]\r\n\r\nThe strange part is that a few of the apps deployed with these strategies did write to Firestore, however upon deploying the app again Firestore did not show new data being written to it.\r\n\r\n# Implementation\r\n\r\n## Ktor Setup\r\n\r\nI have the standard **ktor** required files. I also have an old *MANIFEST.MF* file from an older implementation. Could that be causing issues?\r\n\r\n*src/main/resources/application.conf*\r\n\r\n    ktor {\r\n      application {\r\n      modules = [ Initialization.main ]\r\n      }\r\n    }\r\n\r\n*src/main/resources/webapp/WEB-INF/*\r\n\r\n*appengine-web.xml*\r\n\r\n    <?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n    <appengine-web-app xmlns=\"http://appengine.google.com/ns/1.0\">\r\n        <threadsafe>true</threadsafe>\r\n        <runtime>java8</runtime>\r\n    </appengine-web-app>\r\n\r\n*web.xml*\r\n\r\n    <?xml version=\"1.0\" encoding=\"ISO-8859-1\" ?>\r\n    <web-app xmlns=\"http://java.sun.com/xml/ns/javaee\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd\" version=\"3.0\">\r\n    <servlet>\r\n        <display-name>KtorServlet</display-name>\r\n        <servlet-name>KtorServlet</servlet-name>\r\n        <servlet-class>io.ktor.server.servlet.ServletApplicationEngine</servlet-class>\r\n        <!-- path to application.conf file, required -->\r\n        <init-param>\r\n            <param-name>io.ktor.config</param-name>\r\n            <param-value>application.conf</param-value>\r\n        </init-param>\r\n    </servlet>\r\n    <servlet-mapping>\r\n        <servlet-name>KtorServlet</servlet-name>\r\n        <url-pattern>/</url-pattern>\r\n    </servlet-mapping>\r\n</web-app>\r\n\r\n*logging.properties*\r\n\r\n`.level = INFO`\r\n\r\n*src/main/META-INF/MANIFEST>MF*\r\n\r\n    Manifest-Version: 1.0\r\n    Main-Class: Initialization\r\n\r\n## Dependencies\r\n\r\nFor authentication strategies outlined below **#1-3** the Firebase Admin library is used: `compile 'com.google.firebase:firebase-admin:6.5.0'`\r\n\r\nFor authentication strategy **#4** the Google Cloud Firestore library is used: `compile 'com.google.cloud:google-cloud-firestore:0.58.0-beta'`\r\n\r\n**build.gradle**\r\n\r\n    group 'coinverse'\r\n    version '1.0-SNAPSHOT'\r\n\r\n    buildscript {\r\n        ext.kotlin_version = '1.2.61'\r\n        ext.junitJupiterVersion  = '5.0.3'\r\n        ext.ktor_version = '0.9.4'\r\n        ext.appengine_version = '1.9.60'\r\n        ext.appengine_plugin_version = '1.3.4'\r\n\r\n    repositories {\r\n        mavenCentral()\r\n        jcenter()\r\n    }\r\n    dependencies {\r\n        classpath \"org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version\"\r\n        classpath 'org.junit.platform:junit-platform-gradle-plugin:1.0.3'\r\n        classpath \"com.google.cloud.tools:appengine-gradle-plugin:$appengine_plugin_version\"\r\n        }\r\n    }\r\n\r\n    apply plugin: 'java'\r\n    apply plugin: 'kotlin'\r\n    apply plugin: 'war'\r\n    apply plugin: 'com.google.cloud.tools.appengine'\r\n\r\n    sourceSets {\r\n        main.kotlin.srcDirs = [ 'src/main/kotlin' ]\r\n    }\r\n\r\n    sourceCompatibility = 1.8\r\n\r\n    repositories {\r\n    mavenCentral()\r\n    jcenter()\r\n    maven { url \"https://kotlin.bintray.com/ktor\" }\r\n    }\r\n\r\n    dependencies {\r\n        implementation \"org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version\"\r\n        testCompile group: 'junit', name: 'junit', version: '4.12'\r\n        testCompile(\"org.junit.jupiter:junit-jupiter-api:${junitJupiterVersion}\")\r\n            testRuntime(\"org.junit.jupiter:junit-jupiter-engine:${junitJupiterVersion}\")\r\n            testCompile(\"org.assertj:assertj-core:3.10.0\")\r\n            testCompileOnly('org.apiguardian:apiguardian-api:1.0.0')\r\n            compile 'com.squareup.retrofit2:retrofit:2.3.0'\r\n            compile 'com.squareup.retrofit2:converter-gson:2.3.0'\r\n            compile 'com.squareup.retrofit2:adapter-rxjava:2.3.0'\r\n            compile 'io.reactivex.rxjava2:rxjava:2.2.0'\r\n            compile 'com.google.cloud:google-cloud-firestore:0.58.0-beta'\r\n            // Or compile 'com.google.cloud:google-cloud-firestore:0.58.0-beta'\r\n            compile 'com.google.firebase:firebase-admin:6.5.0'\r\n            compile \"org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version\"\r\n            compile \"io.ktor:ktor-server-servlet:$ktor_version\"\r\n            compile \"io.ktor:ktor-html-builder:$ktor_version\"\r\n            providedCompile \"com.google.appengine:appengine:$appengine_version\"\r\n    }\r\n\r\n    kotlin.experimental.coroutines = 'enable'\r\n\r\n    compileKotlin {\r\n        kotlinOptions.jvmTarget = \"1.8\"\r\n    }\r\n    compileTestKotlin {\r\n        kotlinOptions.jvmTarget = \"1.8\"\r\n    }\r\n\r\n    task run(dependsOn: appengineRun)\r\n\r\n    appengine {\r\n        deploy {\r\n            version = 'price-staging-1021653pm'\r\n            stopPreviousVersion = false\r\n        }\r\n    }\r\n\r\n## Initializing Firebase Strategies\r\n\r\n**1. [Initialize on Google Cloud Platform](https://firebase.google.com/docs/firestore/quickstart#initialize)**\r\n\r\nThis method is promising as credentials are managed automatically.\r\n\r\n    // Use the application default credentials\r\n    GoogleCredentials credentials = GoogleCredentials.getApplicationDefault();\r\n    FirebaseOptions options = new FirebaseOptions.Builder()\r\n        .setCredentials(credentials)\r\n        .setProjectId(projectId)\r\n        .build();\r\n    FirebaseApp.initializeApp(options);\r\n\r\n    Firestore db = FirestoreClient.getFirestore();\r\n\r\n**2. [Initialize on your own server](https://firebase.google.com/docs/firestore/quickstart#initialize)**\r\n\r\nI've confirmed in GCPs *IAM & admin* > *Service accounts* that the key id's match with the Json object being used to authenticate.\r\n\r\nI'm using this strategy successfully in another Firestore connected app deployed to AppEngine. The working app is built as a **.Jar** and deployed directly to AppEngine without using **ktor**, but rather with the steps outlined [here](https://medium.com/r/?url=https%3A%2F%2Fhackernoon.com%2Fdeploy-a-backend-app-as-an-android-engineer-49bd94b4c367).\r\n\r\n    // Use a service account\r\n    InputStream serviceAccount = new FileInputStream(\"path/to/serviceAccount.json\");\r\n    GoogleCredentials credentials = GoogleCredentials.fromStream(serviceAccount);\r\n    FirebaseOptions options = new FirebaseOptions.Builder()\r\n        .setCredentials(credentials)\r\n        .build();\r\n    FirebaseApp.initializeApp(options);\r\n\r\n    Firestore db = FirestoreClient.getFirestore();\r\n\r\nIn my working **.Jar** built app I'm passing in the **Json** object programmatically to avoid issues with the file not being found. I tried the same programmatic implementation for this **ktor** application. It worked with `gradle appengineRun` but not when deployed.\r\n\r\n    val credentials = GoogleCredentials.fromStream(Gson().toJson(FirebaseCredentials(\r\n                \"service_account\",\r\n                \"project-name\",\r\n                \"asdfghjkl\",\r\n                \"keyStringHere\",\r\n                \"firebase-adminsdk-dhr30@project-name.iam.gserviceaccount.com\",\r\n                \"1234567890\",\r\n                \"https://accounts.google.com/o/oauth2/auth\",\r\n                \"https://oauth2.googleapis.com/token\",\r\n                \"https://www.googleapis.com/oauth2/v1/certs\",\r\n               \"https://www.googleapis.com/robot/v1/metadata/x509/firebase-adminsdk-dhr30%40project-name-staging.iam.gserviceaccount.com\"\r\n        )).byteInputStream())\r\n        val options = FirebaseOptions.Builder()\r\n                .setCredentials(credentials)\r\n                .setDatabaseUrl(\"https://project-name-staging.firebaseio.com\")\r\n                .build()\r\n\r\n        FirebaseApp.initializeApp(options)\r\n\r\n**3. Initialize on your own server (Firebase console setup)**\r\n\r\nThe only difference between **#2** is this setup adds `.setDatabaseUrl(\"https://yourProjectName.firebaseio.com\")`.\r\n\r\n[![enter image description here][2]][2]\r\n\r\n\r\n**4. [Initialize cloud Firestore](https://cloud.google.com/firestore/docs/quickstart-servers)**\r\n\r\n    FirestoreOptions firestoreOptions =\r\n    FirestoreOptions.getDefaultInstance().toBuilder()\r\n        .setProjectId(projectId)\r\n        .build();\r\n    Firestore db = firestoreOptions.getService();\r\n\r\n\r\n  [1]: https://i.stack.imgur.com/5stVc.png\r\n  [2]: https://i.stack.imgur.com/kQIF8.png\r\n\r\n## Accessing Firestore Object\r\n\r\nFor **#1-3** the Firebase app is initialized right away in the application's **main()** method. Then, the **Firestore** object is accessed from an object.  \r\n\r\n**FirebaseClient.Kt**\r\n\r\n    object FirebaseClient {\r\n        val firestore: Firestore\r\n        init {\r\n            firestore = FirestoreClient.getFirestore()\r\n        }\r\n    }\r\n\r\nFor **#4** the Firestore object is created in the Kotlin object's `init{...}` and stored in the object as a value.\r\n\r\n**FirebaseClient.Kt**\r\n\r\n    object FirebaseClient {\r\n        val firestore: Firestore\r\n\r\n        init {\r\n            val firestoreOptions = FirestoreOptions.getDefaultInstance().toBuilder()\r\n                .setTimestampsInSnapshotsEnabled(true)\r\n                .setProjectId(\"project-name\")\r\n                .build()\r\n            firestore = firestoreOptions.service\r\n        }\r\n    }\r\n\r\n## Writing to Firestore\r\n\r\n`FirebaseClient.firestore.collection(someCollection).document(someDocument).collection(anotherCollection).add(someObject)`\r\n\r\nI've created a corresponding [StackOverflow post](https://stackoverflow.com/questions/52922552/firebase-auth-not-working-with-ktor-app-on-appengine).\r\n\r\n "},"comment":{"url":"https://api.github.com/repos/GoogleCloudPlatform/community/issues/comments/451007479","html_url":"https://github.com/GoogleCloudPlatform/community/issues/572#issuecomment-451007479","issue_url":"https://api.github.com/repos/GoogleCloudPlatform/community/issues/572","id":451007479,"node_id":"MDEyOklzc3VlQ29tbWVudDQ1MTAwNzQ3OQ==","user":{"login":"ToddKopriva","id":43478937,"node_id":"MDQ6VXNlcjQzNDc4OTM3","avatar_url":"https://avatars1.githubusercontent.com/u/43478937?v=4","gravatar_id":"","url":"https://api.github.com/users/ToddKopriva","html_url":"https://github.com/ToddKopriva","followers_url":"https://api.github.com/users/ToddKopriva/followers","following_url":"https://api.github.com/users/ToddKopriva/following{/other_user}","gists_url":"https://api.github.com/users/ToddKopriva/gists{/gist_id}","starred_url":"https://api.github.com/users/ToddKopriva/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ToddKopriva/subscriptions","organizations_url":"https://api.github.com/users/ToddKopriva/orgs","repos_url":"https://api.github.com/users/ToddKopriva/repos","events_url":"https://api.github.com/users/ToddKopriva/events{/privacy}","received_events_url":"https://api.github.com/users/ToddKopriva/received_events","type":"User","site_admin":false},"created_at":"2019-01-02T22:38:51Z","updated_at":"2019-01-02T22:38:51Z","author_association":"COLLABORATOR","body":"closing as a duplicate of this PR:\r\nhttps://github.com/GoogleCloudPlatform/community/issues/573"}}
{"actor":{"display_login":"ToddKopriva"}}