question

newuser-c332d229-b7d8-4967-87ea-dc5671df493b avatar image
newuser-c332d229-b7d8-4967-87ea-dc5671df493b asked ·

We were unable to link kraw linking at this time.

the error URL is

https://skills-store.amazon.in/external/link-result?success=false&languageCode=en_IN&skillId=amzn1.ask.skill.0a1793cc-b5b2-4360-a64a-87f44ad03601&skillStage=development


please tell me actual problem

I can use firebase hosting website

firebase authration


authration url : https://kraw-home.web.app/alexa.html

token url : https://us-central1-kraw-home.cloudfunctions.net/access_token


my login page html

<!DOCTYPE html> <html>  <head>    <!-- meta and title -->     <!-- update the version number as needed -->    <script defer src="/__/firebase/5.9.2/firebase-app.js"></script>    <!-- include only the Firebase features as you need -->    <script defer src="/__/firebase/5.9.2/firebase-auth.js"></script>    <script defer src="/__/firebase/5.9.2/firebase-firestore.js"></script>    <script src="https://cdn.firebase.com/libs/firebaseui/3.5.2/firebaseui.js"></script>    <link      type="text/css"      rel="stylesheet"      href="https://cdn.firebase.com/libs/firebaseui/3.5.2/firebaseui.css"    />    <!-- initialize the SDK after all desired features are loaded -->    <script defer src="/__/firebase/init.js"></script>     <style media="screen" type="text/css">      /* styling */    </style>  </head>  <body>    <div id="message">      <h2>Welcome</h2>      <h1>Firebase Login</h1>      <div id="info"></div>    </div>    <div id="firebaseui-auth-container"></div>    <p id="load">Firebase SDK Loading&hellip;</p>     <script>      // see https://stackoverflow.com/a/2117523/5168962      function uuidv4() {        return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, c =>          (            c ^            (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (c / 4)))          ).toString(16)        );      }       document.addEventListener("DOMContentLoaded", function() {        try {          let app = firebase.app();          let db = firebase.firestore();          let features = ["auth"].filter(            feature => typeof app[feature] === "function"          );          document.getElementById(            "load"          ).innerHTML = `Firebase SDK loaded with ${features.join(", ")}`;           firebase.auth().onAuthStateChanged(            function(user) {              if (user) {                // User is signed in.                var uid = user.uid;                 // Generate auth code which we will later use to get our auth_token.                let authCode = uuidv4();                 // Save the code in our database.                db.collection(`auth_codes`)                  .doc(uid)                  .set(                    {                      code: authCode,                      uid: uid,                      created: firebase.firestore.FieldValue.serverTimestamp()                    },                    { merge: true }                  );                 // Send token back to client                const urlParams = new URLSearchParams(window.location.search);                // State sent by Alexa which we have to return.                const state = urlParams.get("state");                // Redirect uri sent by Alexa.                const redirect_uri = urlParams.get("redirect_uri");                 // Combine all the uri elements.                let url =                  redirect_uri + "?state=" + state + "&code=" + authCode;                 // Redirect                window.location.href = url;              } else {                // User is signed out, so we show the Firebase UI.                 // FirebaseUI config.                var uiConfig = {                  signInOptions: [                    // Leave the lines as is for the providers you want to offer your users.                    firebase.auth.EmailAuthProvider.PROVIDER_ID                  ],                  callbacks: {                    // Turn of FirebaseUI redirect.                    signInSuccessWithAuthResult: function(                      authResult,                      redirectUrl                    ) {                      return false;                    }                  },                  credentialHelper: firebaseui.auth.CredentialHelper.NONE                };                 // Initialize the FirebaseUI Widget using Firebase.                var ui = new firebaseui.auth.AuthUI(firebase.auth());                // The start method will wait until the DOM is loaded.                ui.start("#firebaseui-auth-container", uiConfig);              }            },            function(error) {              console.log(error);              document.getElementById("info").textContent = "Error: " + error;            }          );        } catch (e) {          console.error(e);          document.getElementById("load").innerHTML =            "Error loading the Firebase SDK, check the console.";        }      });    </script>  </body> </html>


access code

const functions = require("firebase-functions"); const admin = require("firebase-admin"); // see https://www.npmjs.com/package/uuid const uuidv4 = require("uuid/v4"); 
admin.initializeApp(); 
const db = admin.firestore(); 
async function getAccessTokenByAuthCode(req, res) {  let code = req.body.code;   let dbEntry = await db    .collection("auth_codes")    .where("code", "==", code)    .get();   if (dbEntry.empty) {    return res.send(404);  }   let dbDoc = dbEntry.docs[0];   let uid = dbDoc.data().uid;   let additionalClaims = {    alexa: true  };   // Create a custom token. See https://firebase.google.com/docs/auth/admin/create-custom-tokens  let access_token = await admin    .auth()    .createCustomToken(uid, additionalClaims);   let refresh_token = uuidv4();   db.doc(`auth_codes/${uid}`).update({    access_token: access_token,    refresh_token: refresh_token  });   return res.json({    access_token: access_token,    token_type: "Bearer",    refresh_token: refresh_token,    expires_in: 60 * 60,    id_token: ""  }); }
 async function getAccessTokenByRefreshToken(req, res) {  let refresh_token = req.body.refresh_token;   let dbEntry = await db    .collection("auth_codes")    .where("refresh_token", "==", refresh_token)    .get();   if (dbEntry.empty) {    return res.send(404);  }   let dbDoc = dbEntry.docs[0];   let uid = dbDoc.data().uid;   let additionalClaims = {    alexa: true  };   let access_token = await admin    .auth()    .createCustomToken(uid, additionalClaims);   db.doc(`auth_codes/${uid}`).update({    access_token: access_token  });   return res.json({    access_token: access_token,    token_type: "Bearer",    refresh_token: refresh_token,    expires_in: 60 * 60,    id_token: ""  }); }
 exports.access_token = functions.https.onRequest(async (req, res) => {  // check client_id and client_secret   if (req.body.grant_type === "authorization_code") {    return getAccessTokenByAuthCode(req, res);  } else if (req.body.grant_type === "refresh_token") {    return getAccessTokenByRefreshToken(req, res);  } else {    return res.send(404);  } });


amzon code


const Alexa = require("ask-sdk-core"); const firebase = require("firebase"); // Required for side-effects require("firebase/auth"); require("firebase/firestore"); 
// Initialize Cloud Firestore through Firebase var config = {  // ... }; 
firebase.initializeApp(config); var db = firebase.firestore(); 
const LaunchRequestHandler = {  canHandle(handlerInput) {    return handlerInput.requestEnvelope.request.type === "LaunchRequest";  },  async handle(handlerInput) {    console.log("LaunchRequest");     var speechText = "Please link your account!";     const accessToken =      handlerInput.requestEnvelope.context.System.user.accessToken;     // Test if user has linked his account.    if (!accessToken) {      return handlerInput.responseBuilder.speak(speechText).getResponse();    }     // Alexa will save our custom token in the access token field, so we can use it here.    await firebase      .auth()      .signInWithCustomToken(accessToken)      .catch((error) => {        // Handle Errors here.        var errorCode = error.code;        var errorMessage = error.message;        console.log(error.message);        return handlerInput.responseBuilder.speak(speechText).getResponse();      });     let user = firebase.auth().currentUser;     if (user) {      // login successful      speechText = `Welcome ${user.displayName}!`;    } else {      // No user is signed in.      speechText = `Welcome, please link your account!`;    }     // ATTENTION: This is very important. Without this the function will time out.    await firebase.auth().signOut();     return handlerInput.responseBuilder.speak(speechText).getResponse();  } };
account linkingaccount-linki
10 |2000 characters needed characters left characters exceeded

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

1 Answer

Chihiro@Amazon avatar image
Chihiro@Amazon answered ·

Hi there,

Thank you for posting. It looks current Access Token URI is "https://us-central1-kraw-home.cloudfunctions.net/auth_token." There is period at the end which may not be expected.

Checking the log on our end, it looks Alexa service is sending POST request to access token URI: https://us-central1-kraw-home.cloudfunctions.net/auth_token. but the server returned exception. I would recommend checking the server log and please make sure it is not sending an error or an invalid JSON response to Alexa.

Timestamp:

2021/06/21 6:26:31.642 UTC

Troubleshooting Common Account Linking Issues with Alexa Skills

10 |2000 characters needed characters left characters exceeded

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.