<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: App &amp; Flow</title>
    <description>The latest articles on Forem by App &amp; Flow (@appandflow).</description>
    <link>https://forem.com/appandflow</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F282414%2Ff605e792-1102-478b-8b29-e66122a645e6.png</url>
      <title>Forem: App &amp; Flow</title>
      <link>https://forem.com/appandflow</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/appandflow"/>
    <language>en</language>
    <item>
      <title>Make your own Alexa Skill without using Lambda</title>
      <dc:creator>App &amp; Flow</dc:creator>
      <pubDate>Thu, 23 Jan 2020 20:55:33 +0000</pubDate>
      <link>https://forem.com/appandflow/make-your-own-alexa-skill-without-using-lambda-3o60</link>
      <guid>https://forem.com/appandflow/make-your-own-alexa-skill-without-using-lambda-3o60</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PCUTaft9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/1753/0%2AaBXh7xwQW7JunHvW.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PCUTaft9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/1753/0%2AaBXh7xwQW7JunHvW.jpg" alt="illustration" title="Illustration"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;“Your scientists were so preoccupied with whether or not they could, they didn’t stop to think if they should.”&lt;/em&gt; — Ian, Jurrasic Park&lt;/p&gt;

&lt;p&gt;Why should you even bother making your own custom Alexa Skill without using Lambda?&lt;/p&gt;

&lt;p&gt;Actually, a few reasons come to mind :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;You don’t like depending on other services&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You enjoy tinkering / you consider yourself a DIY-er&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--XdmBWn8d--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/346/1%2ANxgX6NSfgIjWdMYgjXy0HQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--XdmBWn8d--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/346/1%2ANxgX6NSfgIjWdMYgjXy0HQ.png" alt="meme" title="Meme"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Your Alexa Skill will be used alongside an existing service that already has its own backend (like a mobile app or a web page) and you’d rather this backend handles everything.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It’s obvious from this list that doing all of this isn’t for everyone. Actually, more people would benefit from using Lambda, as long as you don’t go over their very generous 1 million requests / month free-tier. Check out &lt;a href="https://developer.amazon.com/en-US/docs/alexa/custom-skills/host-a-custom-skill-as-an-aws-lambda-function.html"&gt;Amazon’s list&lt;/a&gt; of why you &lt;strong&gt;should&lt;/strong&gt; use Lambda just to get an idea.&lt;/p&gt;

&lt;p&gt;You’re still reading? Good. Just before we dive deeper, here’s a fictional service that we’ll use as a reference point throughout this article :&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Your startup has a mobile app that keeps track of bus schedules. Groundbreaking, never-seen-before, edgy, right? Anyway, this mobile app communicates with your backend that handles communication with the transit company’s API. Users can create their own account and keep track of their favorite bus routes. Your app is doing well already, but so many users are writing to tell you that it would perfect if only you had an integration with Alexa. This is how you embarked on this journey.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You’ll need the following to be able to complete this tutorial :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;A node.js backend hosted somewhere like on DigitalOcean or AWS. (any backend would do, you can recycle the concepts used here on pretty much anything)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A website that lets users log in to their account&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A few use cases for the skill&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A mobile phone with the Alexa app installed (no need to have an actual Alexa device!)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Use cases
&lt;/h2&gt;

&lt;p&gt;Coming back to our bus schedule startup, some good ideas for use cases could be :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Alexa, when is the next 105 passing?&lt;/em&gt; -&amp;gt; Should tell me the amount of minutes to the next bus passing. For example “The next 105 passes in 10 minutes”.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Alexa, are there any interruptions in the metro today?&lt;/em&gt; -&amp;gt; The transit company’s API can tell us wether or not there are interruptions at the present time. For example “Yes, the purple line is down until 9:15PM”.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Alexa, what is the next bus?&lt;/em&gt; -&amp;gt; If the user has set up 2 busses leaving from their home, this service could tell them which one of these busses is passing next. For example “The next bus is the 105 which is passing in 5 minutes”.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Setting up the Alexa Developer Console
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Create an account if you don’t already have one on &lt;a href="https://developer.amazon.com/"&gt;Developer Amazon&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Go to the &lt;a href="https://www.amazon.com/ap/signin?clientContext=132-5850387-9591745&amp;amp;openid.return_to=https%3A%2F%2Fdeveloper.amazon.com%2Fsettings%2Fconsole%2Fregistration%2Fnextstep&amp;amp;openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&amp;amp;openid.assoc_handle=mas_dev_portal&amp;amp;openid.mode=checkid_setup&amp;amp;marketPlaceId=ATVPDKIKX0DER&amp;amp;openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&amp;amp;pageId=amzn_developer_portal&amp;amp;openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&amp;amp;siteState=clientContext%3D143-6627634-5176758%2CsourceUrl%3Dhttps%253A%252F%252Fdeveloper.amazon.com%252Fsettings%252Fconsole%252Fregistration%252Fnextstep%2Csignature%3Dp7Pj2F7WmqbB6xE2KPGwb6j2FCmKoj2B0j3D&amp;amp;language=en_US"&gt;Alexa Developer Console&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create a new skill : give it a name, use the “custom” template and “Start from scratch”. You should see this :&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--tihKAGmp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/891/1%2A2vbOrTkbXm1zrHlH5OSYmA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--tihKAGmp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/891/1%2A2vbOrTkbXm1zrHlH5OSYmA.png" alt="screenshot" title="Screenshots"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is where you’ll be doing most of the “Alexa developer” work. The following list is a short summary of this &lt;a href="https://developer.amazon.com/en-US/docs/alexa/custom-skills/create-the-interaction-model-for-your-skill.html"&gt;Alexa page&lt;/a&gt; :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Intents&lt;/strong&gt; : An intent represents an action that fulfills a user’s spoken request&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Utterances&lt;/strong&gt; : A set of likely spoken phrases mapped to the intents&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Custom slot types&lt;/strong&gt; : A representative list of possible values for a slot&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So coming back to our use case “Alexa, when is the next 105 passing?”, this &lt;strong&gt;utterance&lt;/strong&gt; would be handled by an &lt;strong&gt;intent&lt;/strong&gt; that we can call &lt;code&gt;findNextBus&lt;/code&gt; for example. The 105 will be a &lt;strong&gt;custom slot type&lt;/strong&gt; that we can define as &lt;code&gt;busNumber&lt;/code&gt; that has the type &lt;em&gt;number&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;As this tutorial isn’t meant to be a “how to create an Alexa skill” but more how to make it work without lambda, I’ll let you read one of the many articles on the subject (or just figure it out as you go along, it’s really nothing special).&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;endpoint&lt;/strong&gt; section should be set to HTTPS and should point towards a route that handles Alexa’s requests (ie : &lt;code&gt;https://api.mywebsite.com/alexaAction&lt;/code&gt;). During development, you can use &lt;strong&gt;ngrok&lt;/strong&gt; to simulate an HTTPS connection, just make sure to set the SSL certificate type to the one that says “[..]is a subdomain of a domain that has a wildcard certificate[..]”.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;account linking&lt;/strong&gt; section is optional in case you don’t plan on having users sign in to their account. For our example, we’ll need to set it up. These are the fields you’ll need to fill in this section :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Authorization URI&lt;/strong&gt; : The URI where customers will be redirected to in the companion app to enter login credentials.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Client Id&lt;/strong&gt; : Unique public string used to identify the client requesting for authentication. You can use your preferred way of generating strings (&lt;a href="https://www.howtogeek.com/howto/30184/10-ways-to-generate-a-random-password-from-the-command-line/"&gt;here’s some for inspiration&lt;/a&gt;) or just let your cat walk over your keyboard, your call. Just keep it somewhere as your backend will have to validate this client id.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That’s about it for the Alexa Developer stuff. Once you’ll have something functional, you can apply for certification.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up your backend
&lt;/h2&gt;

&lt;p&gt;Let’s assume for this example that you’re using a simple MVC-inspired “router → controller → service” kind of pattern on your backend.&lt;/p&gt;

&lt;p&gt;Usually, this would mean your route &lt;code&gt;/alexaAction&lt;/code&gt; would call a controller, who would in turn call the service; the service would do the job, return the information to the controller that takes care of sending the info back. But in our case, we first need to make sure that the network request is actually coming from Amazon, and the easiest way I’ve found is to use an auth middlewear. But it doesn’t end there. The only way to make sure that the request really comes from Alexa is to have access to the raw request body, before body parser does it’s job. This means that your Alexa route cannot be mixed in with your current router, it will have to be separate. Your app.ts will look like this :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;‘&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;alexaAction&lt;/span&gt;&lt;span class="err"&gt;’&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;alexaAuth&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;alexaActionPost&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bodyParser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bodyParser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;urlencoded&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;extended&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;}));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;For the alexaAuth middlewear, I heavily inspired myself from the lib &lt;a href="https://www.npmjs.com/package/alexa-verifier-middleware"&gt;alexa-verifier-middlewear&lt;/a&gt;. It wasn’t exactly what I was looking for, so I made my own middlewear with the code :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;NextFunction&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Response&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Request&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../types&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;verifier&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;alexa-verifier&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;auth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Request&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;any&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NextFunction&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;er&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;The raw request body has already been parsed.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;failure&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;reason&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;er&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rawBody&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;data&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rawBody&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;end&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="na"&gt;er&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;any&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rawBody&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;er&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;certUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;signaturecertchainurl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;signature&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;signature&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

      &lt;span class="nx"&gt;verifier&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;certUrl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;signature&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rawBody&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;failure&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;reason&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Unauthorized&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;With this in place, your backend is listening to the route &lt;code&gt;/alexaAction&lt;/code&gt; and we can be sure that anything that gets to it will be coming from Amazon.&lt;/p&gt;

&lt;p&gt;Up next, you’ll need a way to handle the post itself. I’ll explain the bigger picture, but you should implement it in whichever way you want. Also, I’ll explain the flow that includes user authentification, so if you don’t intend on doing that you’ll be able to skip certain parts.&lt;/p&gt;

&lt;p&gt;To start, you’ll need to get &lt;strong&gt;session, context, request&lt;/strong&gt; from the body’s request. You’ll also need &lt;strong&gt;applicationId&lt;/strong&gt; from context as well as &lt;strong&gt;type&lt;/strong&gt; from request.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;applicationId&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;application&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Then follow these steps :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;validate that the &lt;code&gt;applicationId&lt;/code&gt; is the same as your &lt;code&gt;alexaSkillId&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;check the type : a &lt;strong&gt;LaunchRequest&lt;/strong&gt; type should return an introductory message that will ask the user what they’d like to know about your service (for example “How can I help you with the bus schedules today?”) whereas an &lt;strong&gt;IntentRequest&lt;/strong&gt; signals that the user is asking a question that needs an answer (like “When is the next 105 passing?”)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;if you get an &lt;strong&gt;IntentRequest&lt;/strong&gt;, you’ll be able to find the user’s &lt;code&gt;accessToken&lt;/code&gt; like this : &lt;code&gt;session.user.accessToken&lt;/code&gt; . You should use your own validation system to validate the token (this token is what your frontend (where you handle your login) will be giving Amazon once your user logs in, more on that later)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;remember the list of intents that you created such as findNextBus? You’ll need to provide an answer. The intent can be found here &lt;code&gt;request.intent&lt;/code&gt; . Personally, I made a simple switch that covers all possible intents. If you have custom slots, they can be found at &lt;code&gt;request.intent.slots&lt;/code&gt; .&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A very barebones, watered down, happy-path, no error management version of all this would like something like this :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;handleAlexaQuery&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;applicationId&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;alexaSkillId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;IntentRequest&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;accessToken&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// authenticate your accessToken&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;authenticated&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;intent&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
          &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;findNextBus&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;busNumber&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;intent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;slots&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;busNumber&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;busNumber&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="c1"&gt;// generate logic that will answer when the next bus is passing&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;At the end of the day, you want to take the text you’ve generated and send it back to amazon. It needs to be in this format :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;response&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;outputSpeech&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SSML&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;ssml&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&amp;lt;speak&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;speechText&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/speak&amp;gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;reprompt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;outputSpeech&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SSML&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;ssml&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;&amp;lt;speak&amp;gt;Could you repeat?&amp;lt;/speak&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="nx"&gt;shouldEndSession&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1.0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;sessionAttributes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In this example, &lt;code&gt;speechText&lt;/code&gt; is the text that you want Alexa to say. There are many intonations and ways of pronouncing words using &lt;a href="https://developer.amazon.com/en-US/docs/alexa/custom-skills/speech-synthesis-markup-language-ssml-reference.html"&gt;ssml&lt;/a&gt; but this way is the most basic one. &lt;code&gt;shouldEndSession&lt;/code&gt; should be either true or false, depending on your use case : sometimes you want to close the skill after the user has answered, other times you want to keep it open.&lt;/p&gt;

&lt;p&gt;If a user is not authenticated yet, or started authentification and didn’t go through with it successfully, Amazon forces you to show the user a card that pops up and asks the user to sign in. You have to add&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;card&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="err"&gt;‘&lt;/span&gt;&lt;span class="nx"&gt;LinkAccount&lt;/span&gt;&lt;span class="err"&gt;’&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;to your response, within the response attribute.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up the frontend (website)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;In the Alexa app, the user will add the skill and will see a big button “Enable to use”. This button will redirect to your website, the user will log in, and if successful, they’ll be synced.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Upon loading, your website will have to take three paramaters from the search params (or query params if you prefer) : &lt;code&gt;state&lt;/code&gt;, &lt;code&gt;client_id&lt;/code&gt; and &lt;code&gt;redirect_uri&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Amazon will give you a few acceptable redirectURLs, you need to make sure that your website verifies this and gives an error otherwise. You’ll find the list of redirectURLs in the &lt;strong&gt;Account Linking&lt;/strong&gt; section.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You also need to verify your &lt;code&gt;clientId&lt;/code&gt; (the one you generated earlier on) to make sure it’s valid&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Once the user logs in, the last thing left is to create a new url based on the the params you isolated earlier (&lt;code&gt;redirectURI&lt;/code&gt;, &lt;code&gt;state&lt;/code&gt;, &lt;code&gt;access_token&lt;/code&gt; as well as adding &lt;code&gt;token_type=bearer&lt;/code&gt;) and navigate to that new url.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That’s it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jNhuHFlm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/614/1%2AiQDtbJLhy5CmH0UiVdGtdw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jNhuHFlm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/614/1%2AiQDtbJLhy5CmH0UiVdGtdw.png" alt="meme2" title="meme2"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Recap
&lt;/h2&gt;

&lt;p&gt;Now you’ll have your Alexa Developer Console, your backend and your website working together :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Your bus schedule user can sync their current account to Alexa by using the Alexa app and selecting “Enable to use”. This will open up your …&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;…website. They will log in to their bus schedule account. When they’ll ask “Alexa, when is the next 105 passing?”, this will talk with your…&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;…backend that will handle the query and answer back to Alexa. Your backend must handle all queries that you’ve defined in your…&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;…Alexa Developer Console.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  “Now my boss is asking me to implement Okay Google as well!”
&lt;/h2&gt;

&lt;p&gt;Fear not, most of the info here could be recycled into having your own Google Home action. Theoretically, on the backend side of things, the part that creates the speech response could be made generic enough to work for both services if the same intents are developed on Alexa and Google. The website part is also almost the same, it’s mostly the Actions on Google part that is different. The vocabulary is similar for many terms too, and you can deduce the other ones like Alexa Skill = Google Action.&lt;/p&gt;

&lt;p&gt;One thing to keep track of with Google is that they have 2 types of Actions : Conversational Actions and Direct Actions. What you’ll be looking to implement is Conversational Actions, as Direct Actions are for cases when you have a smart device that you’d like to sync with your smart home and all that jazz. It’s a different ballpark altogether.&lt;/p&gt;

&lt;p&gt;Google has their own Lambda equivalent called Dialogflow, which you won’t be using hehehe. Their &lt;a href="https://developers.google.com/assistant/conversational/overview"&gt;documentation&lt;/a&gt; is also pretty straightforward. Enjoy!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>alexa</category>
      <category>amazon</category>
      <category>virtualassistant</category>
    </item>
    <item>
      <title>ELI5: “Sign in with Apple” for React Native using Expo SDK35 &amp; Node.js</title>
      <dc:creator>App &amp; Flow</dc:creator>
      <pubDate>Thu, 23 Jan 2020 20:55:14 +0000</pubDate>
      <link>https://forem.com/appandflow/eli5-sign-in-with-apple-for-react-native-using-expo-sdk35-node-js-1k00</link>
      <guid>https://forem.com/appandflow/eli5-sign-in-with-apple-for-react-native-using-expo-sdk35-node-js-1k00</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--p6yHcsOI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/2560/0%2AFZ0g4OQ502exhoYL.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--p6yHcsOI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/2560/0%2AFZ0g4OQ502exhoYL.png" alt="alt text" title="Sign in with Apple"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Thanks to &lt;a href="https://medium.com/@vincevalium"&gt;Vincent de Lafontaine&lt;/a&gt;, without his help this article wouldn’t exist.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;We too usually skip to the code snippets, so we won’t judge if you do. Just keep in mind that there’s a bunch of configuration to do on the Apple Developer side of things.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The Expo documentation regarding “Sign in with Apple” is pretty straightforward : you create a button, it calls a function, the user puts in their Apple info, and &lt;em&gt;la dee da&lt;/em&gt; you are authentified.&lt;/p&gt;

&lt;p&gt;Here’s the button almost exactly as what &lt;a href="https://docs.expo.io/versions/latest/sdk/apple-authentication/"&gt;Expo shows you&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;AppleAuthentication&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AppleAuthenticationButton&lt;/span&gt;
  &lt;span class="nx"&gt;buttonType&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;AppleAuthentication&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AppleAuthenticationButtonType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SIGN_IN&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nx"&gt;buttonStyle&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;AppleAuthentication&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AppleAuthenticationButtonStyle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;WHITE&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nx"&gt;cornerRadius&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt;
    &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;150&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;marginRight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;}}&lt;/span&gt;
  &lt;span class="nx"&gt;onPress&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_loginWithApple&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;note that you’ll have to pass it a width and a height, otherwise the button won’t show up (that’s the &lt;a href="https://github.com/expo/expo/issues/5690"&gt;official workaround for now&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;When you press the button, it should call this :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;
&lt;span class="nx"&gt;applePayload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;AppleAuthentication&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;signInAsync&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;requestedScopes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nx"&gt;AppleAuthentication&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AppleAuthenticationScope&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;FULL_NAME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;AppleAuthentication&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AppleAuthenticationScope&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;EMAIL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;code&gt;signInAsync&lt;/code&gt; returns a promise that resolves to an object containing an &lt;code&gt;authorizationCode&lt;/code&gt;(among other things). This is what you want to send to your backend.&lt;/p&gt;

&lt;p&gt;But what then? What do you have to do on the backend to handle this information?&lt;/p&gt;

&lt;p&gt;You know the drill : your route gets an access token from the provider, you send the access token to their API, if valid it returns an object containing some info about the user such as name, email, etc. that you can use in your login or signup flow. You’ve already done it for Google, Facebook, Twitter, Myspace (yeah, no).&lt;/p&gt;

&lt;p&gt;It should be easy.&lt;/p&gt;

&lt;p&gt;Well it ain’t. Apple said “screw this, it’s not good enough for us” and did things a bit differently. You know Apple, they always need to do things differently.&lt;/p&gt;

&lt;p&gt;Here are a few things to know about the apple sign in before we start :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;If you want to validate your authorizationCode with Apple, you need to be enrolled in the Apple Developer Program (💰).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The user can decide to “Sign in with Apple” and choose not to share their email address, in which case you’ll receive a proxy email instead.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Apple will only send you back the user’s email (or proxy email) the first time a specific user authentifies themselves. This means that if the user logs out and logs back in, you won’t get their e-mail the second time around. So keep in mind that if you need the user’s email, you should persist it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The whole frontend part of this flow will only work on standalone builds. It will fail if you try it within Expo.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;“Sign in with Apple” only works for iOS 13, and the button will only appear if that condition is met.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To give you a bigger picture, these will be the steps to follow (all these points will be explained in detail later) :&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pre step&lt;/strong&gt; : Do all the configuration on the Apple Developer portal&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1&lt;/strong&gt; : Create a route on your backend that will receive the payload &lt;br&gt;
obtained from the Expo AppleAuthentification module (as shown previously in the signInAsync example). This payload contains an &lt;code&gt;authorizationCode&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2&lt;/strong&gt; : Create your own json web token (jwt) which will be your &lt;code&gt;clientSecret&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3&lt;/strong&gt; : Authenticate your &lt;code&gt;authorizationCode&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If successful, Apple will send you back a &lt;a href="https://developer.apple.com/documentation/signinwithapplerestapi/tokenresponse"&gt;tokenResponse&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Pre step : Start with all the Apple Developer config stuff
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Login on the &lt;a href="https://developer.apple.com/"&gt;Apple Developer&lt;/a&gt; portal&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Go to &lt;strong&gt;Certificates, Identifiers &amp;amp; Profiles&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Select &lt;strong&gt;Identifiers&lt;/strong&gt;, choose your app and check the “Sign in with Apple” capability. If it’s your first time doing this, you’ll need to create a new app identifier. Make sure to use the same bundle id as in your app.json&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Go to &lt;strong&gt;keys&lt;/strong&gt; and create a new key, give it a pertinent name and make sure to check “Sign in with Apple”. Download the key when you’ll have the opportunity and keep it somewhere safe&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Devs who implement “Sign in with Apple” on web have a few more steps to follow, but we don’t need to worry about them #mobileDevMasterrace (just kidding.)&lt;/p&gt;

&lt;p&gt;You should then have the following items :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Team Id&lt;/strong&gt; : you can find it if you go to &lt;strong&gt;Membership details&lt;/strong&gt;, but it’s also on the app’s Identifier page&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5ZyRtDDE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/794/1%2AeLqH1pzrjY5j2bVnIT5Nfw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5ZyRtDDE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/794/1%2AeLqH1pzrjY5j2bVnIT5Nfw.png" alt="alt text" title="Team ID screenshot"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Key Id&lt;/strong&gt; : You can get it in the Keys section you just created&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--TnkFTPLb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/270/1%2A9gUonTEB5gs0kDRN0-pl4w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--TnkFTPLb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/270/1%2A9gUonTEB5gs0kDRN0-pl4w.png" alt="alt text" title="Key Id Details"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;A secret key file that has a “.p8” extension&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Not related to the Apple Developer stuff, but make sure you also have a bundle id (the same as in your app.json file).&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Step 1 : Your backend receives a payload from your mobile app
&lt;/h2&gt;

&lt;p&gt;Not much to do here other than get the attribute &lt;code&gt;authorizationCode&lt;/code&gt; out of the payload.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;authorizationCode&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;applePayload&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 2 : Create a clientSecret jwt
&lt;/h2&gt;

&lt;p&gt;This part draws inspiration directly from &lt;a href="https://medium.com/techulus/how-to-setup-sign-in-with-apple-9e142ce498d4"&gt;this article&lt;/a&gt; (thanks &lt;a href="https://medium.com/@arjunkomath"&gt;Arjun Komath&lt;/a&gt;!)&lt;/p&gt;

&lt;p&gt;You’ll need your &lt;strong&gt;key id&lt;/strong&gt;, your &lt;strong&gt;team id&lt;/strong&gt; and your &lt;strong&gt;bundle id&lt;/strong&gt;, as well as your &lt;strong&gt;secret key file&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In the following code snippet, I’ll be using &lt;code&gt;fs-extra&lt;/code&gt; as a drop-in replacement for the module &lt;code&gt;fs&lt;/code&gt; from node. The advantage of fs-extra over fs is that &lt;code&gt;readFile&lt;/code&gt; is already promisified and can be awaited.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fs-extra&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;jwt&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;jsonwebtoken&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getClientSecret&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;privateKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;readFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PRIVATE_KEY_FILE_PATH&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;kid&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;APPLE_KEY_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;typ&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;alg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ES256&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;claims&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;iss&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;APPLE_TEAM_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;aud&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://appleid.apple.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;sub&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;APPLE_BUNDLE_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;jwt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sign&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;claims&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;privateKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;algorithm&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ES256&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;header&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;expiresIn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;24h&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 3 : Validate your authorization code
&lt;/h2&gt;

&lt;p&gt;This part is flexible, feel free to fetch in whichever way you prefer. The idea is just to pass it &lt;code&gt;authorizationCode&lt;/code&gt;, &lt;code&gt;clientSecret&lt;/code&gt; and &lt;code&gt;clientId&lt;/code&gt; (=== your bundle id). Also &lt;code&gt;grant_type=authorization_code&lt;/code&gt; as we’re validating the authorization code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;urlBody&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`code=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;authorizationCode&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;amp;client_secret=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;clientSecret&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;amp;client_id=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;clientId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;amp;grant_type=authorization_code`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`https://appleid.apple.com/auth/token`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;urlBody&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;application/x-www-form-urlencoded&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;That’s it. You either get a 200 and a &lt;a href="https://developer.apple.com/documentation/signinwithapplerestapi/tokenresponse"&gt;tokenResponse&lt;/a&gt; or a 400.&lt;/p&gt;

&lt;h2&gt;
  
  
  “But if Apple doesn’t give me the user’s email every time, how do I keep track of users?”
&lt;/h2&gt;

&lt;p&gt;Both the payload sent from your mobile app and the token sent by Apple contain an identity token (the expo module calls it &lt;code&gt;identityToken&lt;/code&gt; while Apple calls it &lt;code&gt;id_token&lt;/code&gt;). These tokens can be decoded using &lt;code&gt;jwt.decode&lt;/code&gt;. Once decoded, they contain a sub attribute which is unique to each user. So you can simply add a sub field to your user, and validate them that way.&lt;/p&gt;

&lt;h3&gt;
  
  
  Further reading
&lt;/h3&gt;

&lt;p&gt;Most helpful post on the subject : &lt;a href="https://medium.com/techulus/how-to-setup-sign-in-with-apple-9e142ce498d4"&gt;How to setup sign-in with apple — Arjun Komath&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For more info regarding the Apple Developer set-up part : &lt;a href="https://developer.okta.com/blog/2019/06/04/what-the-heck-is-sign-in-with-apple"&gt;What the heck is sign in with Apple — Aaron Parecki&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developer.apple.com/documentation/signinwithapplerestapi/generate_and_validate_tokens"&gt;Apple documentation on validating tokens&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>node</category>
      <category>expo</category>
      <category>reactnative</category>
    </item>
    <item>
      <title>Why hiring an in-house developer for your seed funded startup is riskier than you think</title>
      <dc:creator>App &amp; Flow</dc:creator>
      <pubDate>Fri, 29 Nov 2019 16:54:05 +0000</pubDate>
      <link>https://forem.com/appandflow/why-hiring-an-in-house-developer-for-your-seed-funded-startup-is-riskier-than-you-think-4k8p</link>
      <guid>https://forem.com/appandflow/why-hiring-an-in-house-developer-for-your-seed-funded-startup-is-riskier-than-you-think-4k8p</guid>
      <description>&lt;p&gt;I have been wanting to write about this topic for a long time now, but I have been sitting on the idea because:&lt;/p&gt;

&lt;p&gt;a) I am obviously a little biased. We run a software consultancy!&lt;br&gt;
b) I dislike confrontations, and I know this won’t fly with some of you.&lt;/p&gt;

&lt;p&gt;Hear me out…&lt;/p&gt;




&lt;p&gt;It’s a common belief in the startup world that you shouldn’t outsource the development of your first app. It’s better to hire an in-house team, the thinking goes, because an agency will never care as much as an employee. The quality of work won’t be as good. You’ll be just another client to them.  &lt;/p&gt;

&lt;p&gt;I couldn’t disagree more.  &lt;/p&gt;

&lt;p&gt;I understand this argument. I really do. There are a lot of truly terribly agencies out there. Even if you find a good one, committing your app to another company can feel really risky.&lt;br&gt;
But if you’re a seed-funded startup, hiring a full-time developer is even riskier. Here’s why. &lt;/p&gt;

&lt;h3&gt;
  
  
  The Risks of Hiring an In-House Dev
&lt;/h3&gt;

&lt;p&gt;We have helped 20+ teams by building scalable, maintainable and high quality applications. Some of those companies first approached us with a code base that was “95% finished” and hoped we could hop on and quickly finish the job. When we ask why they haven’t completed and launched the application, they almost always tell us the same story: they hired an in-house developer, and that person left, wasn’t working out, or just disappeared.  &lt;/p&gt;

&lt;p&gt;Unfortunately, as soon as we start looking at the code base, it’s often full of spaghetti code, hundreds of libraries, crashes here and there, no typing, no linting, the list goes on. We usually have to suggest a full rebuild. (Note: We don’t do this to make more money — in most situations, a full rebuild is actually faster and cheaper for the client than trying to fix the existing code base!)&lt;br&gt;&lt;br&gt;
If you’re a founder, you’re now in an extremely tough spot. You spent most of your seed funding on a developer. That developer didn’t work out, and now you have to start from scratch again with less time and less money than you started with.  &lt;/p&gt;

&lt;h3&gt;
  
  
  The Best Developers Are Already Taken
&lt;/h3&gt;

&lt;p&gt;I know what you’re thinking. Of course hiring a bad developer is a terrible mistake. But what about hiring a good developer?  &lt;/p&gt;

&lt;p&gt;According to Silicon Valley Bank 2019 Outlook US Report, the number one issue startups are facing is access to talent. “More than 80 percent of US startups say they plan to add employees in 2019, but 29 percent recognize it is extremely challenging to find talent with the necessary skills to grow their businesses”  &lt;/p&gt;

&lt;p&gt;Sure, there are lots of talented developers out there. The problem is that most (if not all) of these awesome developers, just like startup founders (more on that later), want to minimize risk. They have bills to pay, families to support, and an extremely in-demand skill set. Most of them won’t be interested in working for a seed-funded startup that could shut down at any time when they have the opportunity to work for bigger, established companies that can offer more stability, better pay and huge perks.  &lt;/p&gt;

&lt;p&gt;Note: If you have managed to find that one developer in 1,000 who’s extremely talented and willing to work for you, congrats! Feel free to ignore the rest of this article… until that person leaves for a higher-paying job. 😄  &lt;/p&gt;

&lt;h3&gt;
  
  
  You Can’t Afford the Risks of In-House… Yet
&lt;/h3&gt;

&lt;p&gt;Startup founders are often seen as people who are willing to take a huge amount of risk, which is absolutely true — working on a startup is extremely hard and the chances of success are slim.&lt;br&gt;
However, in the day-to-day, seed stage founders should be doing everything they can to avoid unnecessary risk.  &lt;/p&gt;

&lt;p&gt;Seed-funded startups have the time and runway to build and market ONE great application — but not two.&lt;br&gt;
These companies cannot afford to waste 5 months of time and money on a code base that needs to be scrapped. But I’ve seen this exact situation again and again with founders from all kinds of startups.&lt;br&gt;
Hiring an established, reputable agency to build your app is actually the least risky choice.  &lt;/p&gt;

&lt;h3&gt;
  
  
  Why an Agency is Less Risky than a Hire
&lt;/h3&gt;

&lt;p&gt;The product you offer will make or break your company.&lt;br&gt;
Getting users to actually download and use your application is both critical and really difficult to do. A great application will impress your users, keep them engaged and bring them back. A poorly-built application is the best way to make your users uninstall your app seconds after they downloaded it and never look back. Demoing your product to an investor and having it crash (or work in a very limited way) is a very good way to minimize your chances of getting that glorious Series A.&lt;br&gt;
That’s why I truly believe the right choice is to work with a reliable agency, one that’s trusted by other startup founders and the development community.&lt;br&gt;
(The only exception to this is if you or a co-founder can build the product yourself. In that case, I fully agree that you should keep development in-house.)  &lt;/p&gt;

&lt;p&gt;If you aren’t a technical person, it can be very difficult to determine whether a developer has the specific skills your company needs. Even if you succeed in hiring someone, there’s no guarantee that person will stay long enough to complete your app.&lt;br&gt;
But if you partner with the right agency, you are pretty much guaranteed to come out the other side with a workable, functioning app that you can take to market.&lt;br&gt;
You’ll have a product that’s functional and engaging to end users.&lt;br&gt;
You’ll have a product that will look good and that you can demo to investors.  &lt;/p&gt;

&lt;p&gt;When the time is right, you’ll have an experienced agency that can help you smoothly transition your code base to your newly-hired engineering team.  &lt;/p&gt;

&lt;h3&gt;
  
  
  When Is the Right Time to Build an In-House Team?
&lt;/h3&gt;

&lt;p&gt;Being seed-funded is a great achievement. It means that the company you are building seems promising to people outside of your team.&lt;br&gt;
With seed funding, you have the capital you need to take your company to the next level, transform your prototype into a real application and start growing. But it is absolutely the wrong time to hire an in-house developer.  &lt;/p&gt;

&lt;p&gt;So when is the right time?&lt;br&gt;
We believe it’s when you raise your Series A. With Series A funding, you’ll be able to offer competitive salaries, great health benefits, free food, and many other perks to help you attract great developers.&lt;br&gt;
But until you reach that milestone, remember that seed funding is the starting point of (almost) all great tech companies — maximize your chances of success by working with a reliable and established team to build your application.&lt;br&gt;
And when the time comes to build out your team, you’ll have a solid code base that your future engineers will be able to build upon, maintain and scale instead of scrap.&lt;/p&gt;

</description>
      <category>startup</category>
      <category>reactnative</category>
    </item>
    <item>
      <title>“Design for developers” cheat sheet to make your next project look awesome</title>
      <dc:creator>App &amp; Flow</dc:creator>
      <pubDate>Fri, 29 Nov 2019 16:47:13 +0000</pubDate>
      <link>https://forem.com/appandflow/design-for-developers-cheat-sheet-to-make-your-next-project-look-awesome-9oc</link>
      <guid>https://forem.com/appandflow/design-for-developers-cheat-sheet-to-make-your-next-project-look-awesome-9oc</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Wxx69u4N--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/avflyznryh1zq2h0m721.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Wxx69u4N--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/avflyznryh1zq2h0m721.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;While it is always better to hire a professional UI/UX designer for your product, sometimes we do not want to spend too much money before validating our idea or concept (especially when it is a side project!) &lt;/p&gt;

&lt;p&gt;However, it is still important that the product looks nice and clean 😎!&lt;br&gt;
We made a short cheat sheet for developers out there that could benefit from learning a little more about design. Hopefully it will be helpful to some of you.&lt;/p&gt;

&lt;p&gt;Keep up the hard work!&lt;/p&gt;

</description>
      <category>design</category>
      <category>sideprojects</category>
      <category>startup</category>
    </item>
    <item>
      <title>Yes, you should start your React Native project with Expo</title>
      <dc:creator>App &amp; Flow</dc:creator>
      <pubDate>Fri, 29 Nov 2019 16:44:10 +0000</pubDate>
      <link>https://forem.com/appandflow/yes-you-should-start-your-react-native-project-with-expo-4642</link>
      <guid>https://forem.com/appandflow/yes-you-should-start-your-react-native-project-with-expo-4642</guid>
      <description>&lt;p&gt;This seems to be one of the most frequent questions on Reddit and on other developer communities: “Should I start my project with Expo?”. Some say yes, some say no. At &lt;a href="https://appandflow.com"&gt;App &amp;amp; Flow&lt;/a&gt;, every single React Native project is started with Expo, no questions asked. Because frankly, there is very little reason not to. What are the reasons? You can read them on Expo’s own website here. They are:  &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;&lt;em&gt;Your app needs background code execution&lt;/em&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;em&gt;You need a native module that is not yet available in Expo (ie: Bluetooth)&lt;/em&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;em&gt;App size is critical (needs to minimize the bundle size as much as possible)&lt;/em&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;em&gt;You want to use a particular Push Notification service, other than what Expo offers&lt;/em&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Other than that, why wouldn’t you use Expo?&lt;/p&gt;




&lt;h3&gt;
  
  
  Common misconceptions around Expo
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Expo is good for prototyping, not for production&lt;/em&gt;&lt;/strong&gt;&lt;br&gt;
WRONG. I read this a lot on /r/reactnative, and I never understand why. We’ve built quite a few applications that are in production using Expo, some bigger than others, and it makes it so much easier. Updating to the latest React Native version? Handled by Expo. Over the air updates? Oh I’ll need to install Codepush. Nope! Handled by Expo. Want to share your progress with your team or your client? You can setup Testflight and go that way if you have enough time to spend waiting for the build to process every time you upload one, or you can share it instantly via an Experience in the Expo Client application. The idea that Expo cannot be used for production is, in our opinion, not founded on any good reasons other than the ones listed on Expo’s website. Not only will it make your life easier, but if you do client work they will also appreciate the fact that you are doing what you can to speed up the process.  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;If our needs change in the future, we will have to start over&lt;/em&gt;&lt;/strong&gt;&lt;br&gt;
Again, this is wrong. We’ve been in this situation multiple times and the solution is very straight forward. Both situations were because we needed Bluetooth connectivity along the way, which is not yet supported by Expo. All you need to do is eject your project from the Expo Client. Your project will still work the exact same way it used to, but it will now be depending on ExpoKit, which is a Java/Obj-C library that exposes every module from Expo’s API. From now on, your project will be like if you started it with vanilla React Native, allowing you to react-native link your heart out.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;I have no other options but to link&lt;/em&gt;&lt;/strong&gt;&lt;br&gt;
So you and your team have been working on a project for a little while, in Expo, everything is going well, but now you want to have a nice, native looking picker for your users to use. You start to look around and you find the perfect library. It looks native because it is native, it handles both Android and iOS, this will definitely make our life easier. You npm install, and then you see step 2: the dreaded npm link. Now you have a choice to make: do you eject for a picker library, do you use another input type or do you create your own implementation in JS and make it open source for the Expo developer community? The last option of course! Sure it will a bit more time than ejecting, but not only will Expo save you time in the long run, you will also be helping a whole community by making your work open source. The next person looking for a picker for his or her Expo project will have one to use, all because of you! (Shout out to Vince for his JS implementation of the Picker)&lt;/p&gt;

&lt;p&gt;TLDR: Expo offers you, out of the box&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Over the air updates&lt;/li&gt;
&lt;li&gt;An easy and more reliable way of upgrading React Native versions&lt;/li&gt;
&lt;li&gt;Android Studio/XCode configurations&lt;/li&gt;
&lt;li&gt;Certificates management with Apple or Keystores management with Google&lt;/li&gt;
&lt;li&gt;Push Notifications&lt;/li&gt;
&lt;li&gt;Additional, easy to use modules such as AuthSession or BlurView&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Expo offers a great developer experience, and it is very valuable for any mobile startup since moving quickly is key. It is our opinion that starting a project without Expo is complicating things for no benefits at all. If you’ve ever dealt with Android Studio or XCode, you know for a fact that you can reasonably waste a day or two messing around with the IDE’s for trivial stuff that does not count as progress.&lt;br&gt;
The team at Expo is incredibly active and responsive, you can easily reach out to them via their forums or Slack channel, and they also have a Canny up for feature requested by the community. Unless you have a specific case where Expo should not be used, per their own reasons, do yourself and your clients a favor and start your project with it!&lt;/p&gt;

</description>
      <category>reactnative</category>
      <category>expo</category>
      <category>ios</category>
      <category>android</category>
    </item>
  </channel>
</rss>
