How to get an Alexa userId?
Asked Answered
V

3

16

I'm building an Alexa Skill, and it requires that I store the userId of a user. I've tried to retrieve it with event.session.user.userId. However, when I call console.log(event.session.user.userId) the output is literally amzn1.ask.account.[unique-value-here]. I've looked at several similar questions, and none of them provide a clear enough answer for me.

I'm not sure if this is a bug, a developer-only thing, or if the userId is simply anonymized. If so, is there a way to get the actual userId? I imagine there would be, since Amazon has written an entire guide on it here:

https://developer.amazon.com/public/solutions/alexa/alexa-skills-kit/docs/linking-an-alexa-user-with-a-user-in-your-system.

However, after a long day of debugging, I'm not sure what's real and what's not anymore.

var request = require('request');
var firebase = require('firebase');
var config = {
    apiKey: "my-api-key",
    authDomain: "stuff...",
    databaseURL: "more stuff...",
    storageBucket: "even more stuff...",
};
firebase.initializeApp(config);
// Get a reference to the database
var database = firebase.database();

exports.handler = (event, context) => {
    try {
        // New session
        if (event.session.new) {
            // New Session
            console.log("NEW SESSION");
        }

        // Launch Request
        switch (event.request.type) {
            case "LaunchRequest":
                var url = "https://api.random.org/json-rpc/1/invoke";
                var myRequest = {
                    "jsonrpc": "2.0",
                    "method": "generateStrings",
                    "params": {
                        "apiKey": "another-api-key",
                        "n": "1",
                        "length": "3",
                        "characters": "abcdefghijklmnopqrstuvwxyz0123456789"
                    },
                    "id": 24
                }
                var pin;
                request.post(
                    url,
                    {json: myRequest},
                    function (error, response, body) {
                        if (!error && response.statusCode == 200) {
                            console.log(event.session.user.userId); // **Here**, output is literally amzn1.ask.account.[unique-value-here] 
                            pin = body.result.random.data[0];
                            writeUserPin(pin);
                            var welcome = "Welcome";
                            var pinStatement = "Your 3 letter or number pin is: " + processPinForSpeech(pin);
                            context.succeed(
                                generateResponse(
                                    buildSpeechletReponse(welcome + pinStatement, true),
                                    {}
                                )
                            );
                            console.log(pin);
                        }
                        else {
                            console.log(error);
                        }
                    }
                );
                console.log("LAUNCH REQUEST");
                break;
            // Intent Request
            case "IntentRequest":
                console.log("INTENT REQUEST");
                break;

            // Session Ended Request
            case "SessionEndedRequest":
                console.log("SESSION ENDED REQUEST");
                break;

            default:
                context.fail(`INVALID REQUEST TYPE: ${event.request.type}`);
        }
    }
    catch (error) {
        context.fail(`Exception: ${error}`);
    }

}
    // Helpers
buildSpeechletReponse = (outputText, shouldEndSession) => {
    return {
        outputSpeech : {
            type: "PlainText",
            text: outputText
        },
        shouldEndSession: shouldEndSession
    };
}

generateResponse = (speechletResponse, sessionAttributes) => {
    return {
        version: "1.0",
        sessionAttributes: sessionAttributes,
        response: speechletResponse
    };
}

function writeUserPin(pin) {
    console.log("writing stuff");
    firebase.database().ref('newPins/' + pin).set({
        num : ""
    });
}

function processPinForSpeech(pin) {
    var wordNumArr = ["zero", "one", "two", "three", "four",
     "five", "six", "seven", "eight", "nine"];
    processedPin = "";
    for (i = 0; i < pin.length; i++){
        var currentChar = pin.charAt(i);
        if (isNaN(Number(currentChar))){
            processedPin += currentChar + ". ";
        }
        else {
            processedPin += wordNumArr[Number(currentChar)] + ". ";
        }
    }
    return processedPin
}

The following is the output on the CloudWatch logs:


16:16:19
START RequestId: 48e335c5-d819-11e6-bc01-a939911adc24 Version: $LATEST

16:16:19
2017-01-11T16:16:19.639Z    48e335c5-d819-11e6-bc01-a939911adc24    NEW SESSION

16:16:19
2017-01-11T16:16:19.758Z    48e335c5-d819-11e6-bc01-a939911adc24    LAUNCH REQUEST

16:16:20
2017-01-11T16:16:20.457Z    48e335c5-d819-11e6-bc01-a939911adc24    amzn1.ask.account.[unique-value-here]

16:16:20
2017-01-11T16:16:20.457Z    48e335c5-d819-11e6-bc01-a939911adc24    writing stuff

16:16:20
2017-01-11T16:16:20.520Z    48e335c5-d819-11e6-bc01-a939911adc24    dd2

16:16:20
END RequestId: 48e335c5-d819-11e6-bc01-a939911adc24

16:16:20
REPORT RequestId: 48e335c5-d819-11e6-bc01-a939911adc24  Duration: 1005.48 ms    Billed Duration: 1100 ms Memory Size: 128 MB    Max Memory Used: 38 MB
Villosity answered 11/1, 2017 at 4:28 Comment(1)
Upvoted for making me smile: 'However, after a long day of debugging, I'm not sure what's real and what's not anymore.' Oh, and also because this was a nicely detailed question!Incorrect
V
4

Well, turns out I was doing everything correctly (for once). The reason why the userId was literally amzn1.ask.account.[unique-value-here] was because I was testing it on a "Alexa Start Session" test event in the AWS Lambda console. When I asked my Echo Dot to launch the skill, it generated the actual key. Problem solved.

Villosity answered 11/1, 2017 at 18:15 Comment(5)
Hello Miki, I tried with Echo dot and I still see amzn1.ask.account.A.... <unique value>.. How did you solve it? I wanted to get the user id/email/name to identify the user.Harned
@Harned For me, launching the skill on the actual device gave me an actual key, and not the placeholder value. If you're using the Dot, and it's still giving you a placeholder value, unfortunately I'm not sure what the issue is.Villosity
Miki, what do you mean by actual key? Are you getting the username/email id?Harned
@Harned By actual key, I mean I'm getting a real username and email, and not a placeholder value such as amzn1.ask.account.[unique-value-here]Villosity
@MikiP so you are saying that upon successful account linking you are seeing a real userId with which the user logged in and not amzn1.ask.account.[unique-value-here] generated by Alexa upon enabling of a skill and this is only happening while testing on Echo Dot? I'm testing via a simulator and Alexa console as described here: #54699587 and #54701095 and not observing that behavior.Latchkey
S
11

You are doing it right. This amzn1.ask.account.[unique-value-here] is in-fact the full userId. You can observe this for yourself by enabling your skill from an Echo, logging several requests to your alexa skill, and observing that the userId between these requests is the same value.

Per the JSON Reference:

userId: A string that represents a unique identifier for the user who made the request. The length of this identifier can vary, but is never more than 255 characters. The userId is automatically generated when a user enables the skill in the Alexa app.

Note: Disabling and re-enabling a skill generates a new identifier.

If you only need to persist user attributes between sessions, this value will be sufficient and you can use it to uniquely identify this user so long as they have the skill enabled.

If you need to link an account, the value you're looking for is accessToken and lives in that same user object following successful account link. Per the same JSON Reference as above:

accessToken: a token identifying the user in another system. This is only provided if the user has successfully linked their account. See Linking an Alexa User with a User in Your System for more details.

Sidestep answered 11/1, 2017 at 14:45 Comment(11)
First of all, thank you so much for your answer! It is very detailed. One thing I'm not sure I understand is how I can uniquely identify a user by saving their event.session.user.userId to Firebase, if all of these values are the same. Could you explain that a bit further?Villosity
They are only the same for an individual user of your skill; so for example, someone else using your skill with a different echo would have a different unique value after amzn1.ask.account. So for any given user you can save this value to any data store -- not just Firebase -- and it will be unique to that user.Sidestep
So why is my value literally "[unique-value-here]", and not a random string? Is it because I'm a developer?Villosity
@MikiP Can you edit your question with steps to reproduce how you're making your requests and testing? Sorry, I wasn't clear on your unique value not being a random string. It should be, your procedure must be injecting that somehow. We can clear that up with some more info.Sidestep
@MikiP Some other thoughts: Are you developing via Lambda? If so, can you check your CloudWatch logs for any useful debugging info? Are you inadvertently setting UserId anywhere in your code? Some tutorials have you paste in a literal string like that to your code to get started (for example, this is common in applicationId), and expect that [unique-value-here] is replaced by the developer, could just be something like that.Sidestep
There, I added the code that made this value print.Villosity
@MikiP Take a look at using the alexa-sdk.Sidestep
I looked through it, and it looks like they are just using event.session.user.userId, or event.context.System.user.userId to get the userId. I've tried both of these approaches, and they both give me the same non-random value. Is there a specific place I should look at that I missed?Villosity
If I have two different Skills, is it possible for me to get a userId that would be the same for both Skills... so I could track state or progress in one Skill and incorporate it into the second skill?Latakia
I have a couple of related inquiries, perhaps someone could still address it: #54699587 and #54701095 . Thanks!Latchkey
Do you happen to know the answer to this related question? Thanks! #75968498Witch
V
4

Well, turns out I was doing everything correctly (for once). The reason why the userId was literally amzn1.ask.account.[unique-value-here] was because I was testing it on a "Alexa Start Session" test event in the AWS Lambda console. When I asked my Echo Dot to launch the skill, it generated the actual key. Problem solved.

Villosity answered 11/1, 2017 at 18:15 Comment(5)
Hello Miki, I tried with Echo dot and I still see amzn1.ask.account.A.... <unique value>.. How did you solve it? I wanted to get the user id/email/name to identify the user.Harned
@Harned For me, launching the skill on the actual device gave me an actual key, and not the placeholder value. If you're using the Dot, and it's still giving you a placeholder value, unfortunately I'm not sure what the issue is.Villosity
Miki, what do you mean by actual key? Are you getting the username/email id?Harned
@Harned By actual key, I mean I'm getting a real username and email, and not a placeholder value such as amzn1.ask.account.[unique-value-here]Villosity
@MikiP so you are saying that upon successful account linking you are seeing a real userId with which the user logged in and not amzn1.ask.account.[unique-value-here] generated by Alexa upon enabling of a skill and this is only happening while testing on Echo Dot? I'm testing via a simulator and Alexa console as described here: #54699587 and #54701095 and not observing that behavior.Latchkey
D
0

You should try to read the request that is displayed in the Test console of ASK. From there, you can access the different variables that are being sent to your lambda function. Also, you can manipulate or use them as per your requirement.

Diathermic answered 8/9, 2019 at 12:4 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.