diff --git a/AlexaClientSDKConfig_default.json b/AlexaClientSDKConfig_default.json
new file mode 100644
index 0000000..4484d1b
--- /dev/null
+++ b/AlexaClientSDKConfig_default.json
@@ -0,0 +1,80 @@
+ {
+ "authDelegate":{
+ // The Client Secret of the Product from developer.amazon.com
+ "clientSecret":"70c955eaa6b998bb3eff97f051b18a5f72b21d38e3ba102da1e83aafdd0efa1f",
+ // Unique device serial number. e.g. 123456
+ "deviceSerialNumber":"CXNK000ABCDE",
+ // Refresh Token populated by running AuthServer.py
+ "refreshToken":"",
+ // The Client ID of the Product from developer.amazon.com
+ "clientId":"amzn1.application-oa2-client.a308f3dc39a54349b970f19b13c86f5d",
+ // Product ID from developer.amazon.com
+ "productId":"GC4026E"
+ },
+ "alertsCapabilityAgent":{
+ // Path to Alerts database file. e.g. /home/ubuntu/Build/alerts.db
+ // Note: The directory specified must be valid.
+ // The database file (alerts.db) will be created by SampleApp, do not create it yourself.
+ // The database file should only be used for alerts (don't use it for other components of SDK)
+ "databaseFilePath":"",
+ // Path to default Alarm sound file. e.g. /home/ubuntu/alert_sounds/alarm_normal.mp3
+ // Note: The audio file must exist and be a valid file.
+ "alarmSoundFilePath":"",
+ // Path to short Alarm sound file. e.g. /home/ubuntu/alert_sounds/alarm_short.wav
+ // Note: The audio file must exist and be a valid file.
+ "alarmShortSoundFilePath":"",
+ // Path to default timer sound file. e.g. /home/ubuntu/alert_sounds/timer_normal.mp3
+ // Note: The audio file must exist and be a valid file.
+ "timerSoundFilePath":"",
+ // Path to short timer sound file. e.g. /home/ubuntu/alert_sounds/timer_short.wav
+ // Note: The audio file must exist and be a valid file.
+ "timerShortSoundFilePath":""
+ },
+ "settings":{
+ // Path to Settings database file. e.g. /home/ubuntu/Build/settings.db
+ // Note: The directory specified must be valid.
+ // The database file (settings.db) will be created by SampleApp, do not create it yourself.
+ // The database file should only be used for settings (don't use it for other components of SDK)
+ "databaseFilePath":"",
+ "defaultAVSClientSettings":{
+ // Default language for Alexa.
+ // See https://developer.amazon.com/docs/alexa-voice-service/settings.html#settingsupdated for valid values.
+ "locale":""
+ }
+ },
+ "certifiedSender":{
+ // Path to Certified Sender database file. e.g. /home/ubuntu/Build/certifiedsender.db
+ // Note: The directory specified must be valid.
+ // The database file (certifiedsender.db) will be created by SampleApp, do not create it yourself.
+ // The database file should only be used for certifiedSender (don't use it for other components of SDK)
+ "databaseFilePath":""
+ }
+ }
+
+
+// Notes for logging
+// The log levels are supported to debug when SampleApp is not working as expected.
+// There are 14 levels of logging with DEBUG9 providing the highest level of logging and CRITICAL providing
+// the lowest level of logging i.e. if DEBUG9 is specified while running the SampleApp, all the logs at DEBUG9 and
+// below are displayed, whereas if CRITICAL is specified, only logs of CRITICAL are displayed.
+// The 14 levels are:
+// DEBUG9, DEBUG8, DEBUG7, DEBUG6, DEBUG5, DEBUG4, DEBUG3, DEBUG2, DEBUG1, DEBUG0, INFO, WARN, ERROR, CRTITICAL.
+
+// To selectively see the logging for a particular module, you can specify logging level in this json file.
+// Some examples are:
+// To only see logs of level INFO and below for ACL and MediaPlayer modules,
+// - grep for ACSDK_LOG_MODULE in source folder. Find the log module for ACL and MediaPlayer.
+// - Put the following in json:
+
+// "acl":{
+// "logLevel":"INFO"
+// },
+// "mediaPlayer":{
+// "logLevel":"INFO"
+// }
+
+// To enable DEBUG, build with cmake option -DCMAKE_BUILD_TYPE=DEBUG. By default it is built with RELEASE build.
+// And run the SampleApp similar to the following command.
+// e.g. TZ=UTC ./SampleApp /home/ubuntu/.../AlexaClientSDKConfig.json /home/ubuntu/KittAiModels/ DEBUG9"
+
+
diff --git a/config.c b/config.c
index fb3c193..01a4daa 100644
--- a/config.c
+++ b/config.c
@@ -67,7 +67,8 @@ json_object* getCleanConfig(char *filename) {
//printf(cJSON_Print(json));
//printf("\n");
}else{
- printf("Failed to parse response\n");
+ printf("Failed to parse config\n");
+ return NULL;
}
return json;
@@ -123,11 +124,20 @@ char *get_config_param_value(json_object *config, char *name){
}
int update_config_param(json_object *config, char *name, char *value) {
- json_object_object_del(config, name);
+ json_object *authDelegate = json_object_object_get(config, "authDelegate");
+ if(authDelegate == NULL) {
+ return -1;
+ }
+ if (strcmp(name, "refreshToken") == 0){
+ json_object_object_del(authDelegate, "refreshToken");
- json_object_object_add(config, name, json_object_new_string(value));
+ json_object_object_add(authDelegate, "refreshToken", json_object_new_string(value));
+
+ return 0;
+ }
- return 0;
+ return -1;
}
+
diff --git a/lwa.c b/lwa.c
index 19df30f..16abe6c 100644
--- a/lwa.c
+++ b/lwa.c
@@ -22,7 +22,7 @@ char * clientSecret = "70c955eaa6b998bb3eff97f051b18a5f72b21d38e3ba102da1e83aafd
#endif
char * scope = "alexa:all";
char * responseType = "code";
-char * urlencode(char *json_string)
+static char * urlencode(char *json_string)
{
static char output[1024];
memset(output, 0, sizeof(output));
@@ -45,7 +45,7 @@ char * urlencode(char *json_string)
}
-char* getRedirectUrl(){
+static char* getRedirectUrl(json_object *config){
static char lwaUrl[1000];
char *scopeData;
json_object *alexa_all, *attr;
@@ -54,13 +54,13 @@ char* getRedirectUrl(){
#ifdef HARDCODE_CONFIG
json_object_object_add(alexa_all, "productID", json_object_new_string(productId));
#else
- json_object_object_add(alexa_all, "productID",json_object_new_string(get_config_param_value(json_config, "productId")));
+ json_object_object_add(alexa_all, "productID",json_object_new_string(get_config_param_value(config, "productId")));
#endif
json_object_object_add(alexa_all, "productInstanceAttributes", attr=json_object_new_object());
#ifdef HARDCODE_CONFIG
json_object_object_add(attr, "deviceSerialNumber", json_object_new_string(deviceSerialNumber));
#else
- json_object_object_add(attr, "deviceSerialNumber", json_object_new_string(get_config_param_value(json_config, "deviceSerialNumber")));
+ json_object_object_add(attr, "deviceSerialNumber", json_object_new_string(get_config_param_value(config, "deviceSerialNumber")));
#endif
scopeData = json_object_to_json_string(root);
json_object_put(root);
@@ -73,7 +73,7 @@ char* getRedirectUrl(){
#ifdef HARDCODE_CONFIG
sprintf(param, "client_id=%s", clientId);
#else
- sprintf(param, "client_id=%s", get_config_param_value(json_config, "clientId"));
+ sprintf(param, "client_id=%s", get_config_param_value(config, "clientId"));
#endif
printf("param:%s\n",param);
strcat(lwaUrl, param);
@@ -103,7 +103,7 @@ char* getRedirectUrl(){
}
-int parseResponse(char *response) {
+static int parseResponse(char *response, json_object *config) {
json_object *json = NULL;
int ret;
json = json_tokener_parse(response);
@@ -113,15 +113,15 @@ int parseResponse(char *response) {
char *refreshToken = json_object_get_string(refreshTokenObject);
if(refreshToken) {
printf("\n==============>Get Refresh Token: [%s]\n", refreshToken);
- ret = update_config_param(json_config, "refreshToken", refreshToken);
+ ret = update_config_param(config, "refreshToken", refreshToken);
if (ret != 0){
printf("\nERROR: Failed to update refresh token\n");
json_object_put(json);
return -1;
}
- ret = writeConfig(json_config, config_out_path);
+ ret = writeConfig(config, config_path);
if (ret != 0){
- printf("\nERROR: Failed to write config to [%s]\n", config_out_path);
+ printf("\nERROR: Failed to write config to [%s]\n", config_path);
json_object_put(json);
return -1;
}
@@ -139,14 +139,14 @@ int parseResponse(char *response) {
}
}
char resp[10240]={0};
-size_t write_data(void* buffer, size_t size, size_t nmemb, void* response) {
+static size_t write_data(void* buffer, size_t size, size_t nmemb, void* response) {
int len = size*nmemb;
memset(resp, 0, sizeof(resp));
memcpy(response, buffer, len);
return len;
}
-int requestRefreshToken(char *code) {
+static int requestRefreshToken(char *code, json_object *config) {
CURL *curl;
CURLcode res;
int ret;
@@ -170,12 +170,12 @@ int requestRefreshToken(char *code) {
#ifdef HARDCODE_CONFIG
clientId,
#else
- get_config_param_value(json_config, "clientId"),
+ get_config_param_value(config, "clientId"),
#endif
#ifdef HARDCODE_CONFIG
clientSecret,
#else
- get_config_param_value(json_config, "clientSecret"),
+ get_config_param_value(config, "clientSecret"),
#endif
urlencode(redirect_uri)
);
@@ -205,7 +205,7 @@ int requestRefreshToken(char *code) {
printf("OK\n");
}
printf("\n==============>Get RESPONSE: %s\n", resp);
- ret = parseResponse(resp);
+ ret = parseResponse(resp, config);
if (ret != 0){
printf("ERROR: parseResponse failed\n");
curl_easy_cleanup(curl);
@@ -226,9 +226,20 @@ int requestRefreshToken(char *code) {
}
}
-int handleUserRequest(int client) {
+static int returnResult(int client, int status, char *info) {
+ char content[1024]={0};
+ write(client, "HTTP/1.0 200\n",13);
+ write(client, "\n", 1);
+ if (status == 0){
+ sprintf(content, "
AVS LWA SuccessSuccess\n");
+ }else{
+ sprintf(content, "AVS LWA FailureFailed.%s\n", info);
+ }
+ write(client, content, strlen(content));
+}
+int handleUserRequest(int client, json_object *config) {
printf("\n==============>Receive User Request");
- char *redirectUrl = getRedirectUrl();
+ char *redirectUrl = getRedirectUrl(config);
if (redirectUrl == NULL) {
return -1;
}
@@ -240,18 +251,7 @@ int handleUserRequest(int client) {
write(client, "\n", 1);
return 0;
}
-int returnResult(int client, int status, char *info) {
- char content[1024]={0};
- write(client, "HTTP/1.0 200\n",13);
- write(client, "\n", 1);
- if (status == 0){
- sprintf(content, "AVS LWA SuccessSuccess\n");
- }else{
- sprintf(content, "AVS LWA FailureFailed.%s\n", info);
- }
- write(client, content, strlen(content));
-}
-int handleAuthCodeGrant(int client, char *request) {
+int handleAuthCodeGrant(int client, char *request, json_object *config) {
char *tag, *code;
int ret;
printf("\n==============>Receive authresponse");
@@ -265,7 +265,7 @@ int handleAuthCodeGrant(int client, char *request) {
returnResult(client, -1, "Failed to extract auth code");
return -1;
}
- ret = requestRefreshToken(code);
+ ret = requestRefreshToken(code, config);
if (ret != 0){
printf("\nERROR: Failed to get refresh token\n");
returnResult(client, -1, "Failed to get refresh token");
diff --git a/lwa.h b/lwa.h
index 0f4a469..fd7c07d 100644
--- a/lwa.h
+++ b/lwa.h
@@ -1,4 +1,4 @@
-extern char config_out_path[256];
+extern char config_path[256];
char redirect_uri[256];
-int handleUserRequest(int client);
-int handleAuthCodeGrant(int client, char *request);
+int handleUserRequest(int client, json_object *config);
+int handleAuthCodeGrant(int client, char *request, json_object *config);
diff --git a/main.c b/main.c
index 773621e..f8ba872 100644
--- a/main.c
+++ b/main.c
@@ -17,16 +17,18 @@
#define CONNMAX 1000
#define BYTES 1024
#define PORT "3000"
-#define CONFIG_IN "AlexaClientSDKConfig.json"
-#define CONFIG_OUT "AlexaClientSDKConfig_out.json"
+#define CONFIG "AlexaClientSDKConfig.json"
+#define CONFIG_DEFAULT "AlexaClientSDKConfig_default.json"
#define REDIRECT_URI "http://localhost:3000/authresponse"
+#define WEBROOT "/etc/alexa/web/"
-char config_in_path[256]={0};
-char config_out_path[256]={0};
+char config_path[256]={0};
+char config_default_path[256]={0};
char redirect_uri[256]={0};
char port[16]={0};
+char web_root[256]={0};
int listenfd, clients[CONNMAX];
-json_object *json_config = NULL;
+
void error(char *);
@@ -46,20 +48,19 @@ int main(int argc, char** argv)
int slot=0;
- strcpy(config_in_path, CONFIG_IN);
- strcpy(config_out_path, CONFIG_OUT);
+ strcpy(config_path, CONFIG);
+ strcpy(config_default_path, CONFIG_DEFAULT);
strcpy(port, PORT);
strcpy(redirect_uri, REDIRECT_URI);
+ strcpy(web_root, WEBROOT);
+
//Parsing the command line arguments
- while ((c = getopt (argc, argv, "p:i:o:r:")) != -1) {
+ while ((c = getopt (argc, argv, "p:c:r:w:d:")) != -1) {
switch (c)
{
- case 'i':
- strcpy(config_in_path, optarg);
- break;
- case 'o':
- strcpy(config_out_path, optarg);
+ case 'c':
+ strcpy(config_path, optarg);
break;
case 'p':
strcpy(port,optarg);
@@ -67,24 +68,25 @@ int main(int argc, char** argv)
case 'r':
strcpy(redirect_uri,optarg);
break;
+ case 'w':
+ strcpy(web_root, optarg);
+ break;
+ case 'd':
+ strcpy(config_default_path, optarg);
+ break;
default:
printf("\nERROR: Unknown parameter\n");
exit(-1);
}
}
- printf("AVS Auth Server started.\nPort: %s%s%s \nConfig in: %s%s%s \nConfig out: %s%s%s\nRedirect URI: %s%s%s\n",
+ printf("AVS Auth Server started.\nWebroot:%s%s%s \nPort: %s%s%s \nConfig: %s%s%s \nConfig default: %s%s%s \nRedirect URI: %s%s%s\n",
+ "\033[92m",web_root,"\033[0m",
"\033[92m",port,"\033[0m",
- "\033[92m",config_in_path,"\033[0m",
- "\033[92m",config_out_path,"\033[0m",
+ "\033[92m",config_path,"\033[0m",
+ "\033[92m",config_default_path,"\033[0m",
"\033[92m",redirect_uri,"\033[0m");
- json_config = getCleanConfig(config_in_path);
- if (json_config == NULL) {
- printf("ERROR: failed to parse the input config");
- exit(-1);
- }
-
// Setting all elements to -1: signifies there is no client connected
int i;
for (i=0; i 0){
+ printf("Get %d data\n", nread);
+ write(client, data_to_send, nread);
+
+ }
+ close(fd);
+
+}
+
+int sendRedirect(int client, char *url)
+{
+ char content[1000];
+ sprintf(content, "Location: %s\n",url);
+ write(client, "HTTP/1.0 307\n",13);
+ write(client, content, strlen(content)+1);
+ write(client, "\n", 1);
+ return 0;
+}
+
+int copyFile(char *from, char *to)
+{
+ FILE *fpFrom, *fpTo;
+ char buffer[4096];
+ int bytes;
+ fpFrom = fopen(from, "r");
+ fpTo = fopen(to, "w+");
+
+ printf("\nCopy File from %s to %s\n", from , to);
+
+ if(fpFrom == NULL){
+ printf("\nFailed to open file %s", from);
+ return -1;
+ }
+ if(fpTo == NULL) {
+ printf("\nFailed to open file %s", to);
+ fclose(fpFrom);
+ return -1;
+ }
+ while((bytes = fread(buffer, 1, sizeof(buffer), fpFrom)) > 0){
+ printf("#####get %d bytes\n", bytes);
+ fwrite(buffer, 1, bytes, fpTo);
+ }
+ fclose(fpFrom);
+ fclose(fpTo);
+
+}
+
+json_object* get_config(){
+ json_object *config = getCleanConfig(config_path);
+ if (config == NULL) {
+ printf("\nINFO: Failed to open config \"%s\", use default config", config_path);
+ config = getCleanConfig(config_default_path);
+ if(config == NULL)
+ {
+ printf("\nERROR: Failed to open default config\"%s\". Exit.", config_default_path);
+ }
+ }
+ return config;
+}
+
+
//client connection
void respond(int n)
{
@@ -194,17 +277,46 @@ void respond(int n)
}
else
{
+ printf("\nRequest: %s", reqline[1]);
+
+ json_object *json_config = NULL;
+ json_config = get_config();
+ if(json_config == NULL)
+ {
+ printf("\nERROR: Failed to get config. Exit.");
+ exit(-1);
+ }
if ( strncmp(reqline[1], "/\0", 2)==0 ) {
- ret = handleUserRequest(clients[n]);
+
+ char * refresh_token = get_config_param_value(json_config, "refreshToken");
+ if (refresh_token == NULL || strlen(refresh_token) == 0){
+ ret = sendFromDirectory(clients[n], web_root, "splash_screen.html");
+ }
+ else
+ {
+ ret = sendFromDirectory(clients[n], web_root, "logout.html");
+ }
+
}else if (strncmp(reqline[1], "/authresponse", 13)==0) {
- ret = handleAuthCodeGrant(clients[n], reqline[1]);
+ ret = handleAuthCodeGrant(clients[n], reqline[1], json_config);
if (ret == 0) {
printf("\nGOOD: successfully generated the config with refresh token. Exit.\n");
- exit(0);
+ ret = sendFromDirectory(clients[n], web_root, "things_to_try.html");
}
+ }else if(strncmp(reqline[1], "/login", 6)==0) {
+ ret = handleUserRequest(clients[n], json_config);
+ }else if(strncmp(reqline[1], "/logout", 7)==0) {
+ copyFile(config_default_path, config_path);
+ ret = sendRedirect(clients[n], "/splash_screen.html");
}
+ else{
+ ret = sendFromDirectory(clients[n], web_root, reqline[1]);
+ }
+ json_object_put(json_config);
}
+
+
}
}
diff --git a/web/AuthServer.py b/web/AuthServer.py
new file mode 100644
index 0000000..3017ea5
--- /dev/null
+++ b/web/AuthServer.py
@@ -0,0 +1,215 @@
+#
+# Copyright 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License").
+# You may not use this file except in compliance with the License.
+# A copy of the License is located at
+#
+# http://aws.amazon.com/apache2.0
+#
+# or in the "license" file accompanying this file. This file is distributed
+# on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+# express or implied. See the License for the specific language governing
+# permissions and limitations under the License.
+#
+
+from flask import Flask, redirect, request, send_from_directory
+import requests
+import json
+import commentjson
+import re
+
+from os.path import abspath, isfile, dirname
+import sys
+from urllib import urlencode
+from shutil import copyfile
+
+# Shuts down the web-server.
+def shutdown():
+ func = request.environ.get('werkzeug.server.shutdown')
+ if func is None:
+ return 'You can close this window and terminate the script.'
+ else:
+ func()
+ return 'Server is shutting down, so you can close this window.'
+
+app = Flask(__name__)
+
+# Static redirect_uri.
+redirectUri = 'http://localalexa.lan:3000/authresponse'
+
+# Static JSON key for the config file.
+authDelegateKey = 'authDelegate'
+
+# Amazon LWA API URL.
+amazonLwaApiUrl = 'https://api.amazon.com/auth/o2/token'
+
+# Amazon LWA API Request header.
+amazonLwaApiHeaders = {'Content-Type': 'application/x-www-form-urlencoded'}
+
+# Default configuration filename, to be filled by CMake
+defaultConfigFilename = "/etc/alexa/AlexaClientSDKConfig.json"
+
+# JSON keys for config file
+CLIENT_ID = 'clientId'
+CLIENT_SECRET = 'clientSecret'
+PRODUCT_ID = 'productId'
+DEVICE_SERIAL_NUMBER = 'deviceSerialNumber'
+REFRESH_TOKEN = 'refreshToken'
+
+# Read the configuration filename from the command line arguments -if it exists.
+if 2 == len(sys.argv):
+ configFilename = abspath(sys.argv[1])
+else:
+ # Assuming the script hasn't moved from the original location
+ # use the default location of SDKConfig.json using relative paths
+ configFilename = defaultConfigFilename
+
+# Check if the configuration file exists.
+if not isfile(configFilename):
+ print 'The file "' + \
+ configFilename + \
+ '" does not exists. Please create this file and fill required data.'
+ sys.exit(1)
+
+try:
+ configFile = open(configFilename,'r')
+
+except IOError:
+ print 'File "' + configFilename + '" not found!'
+ sys.exit(1)
+else:
+ with configFile:
+ configData = commentjson.load(configFile)
+ if not configData.has_key(authDelegateKey):
+ print 'The config file "' + \
+ configFilename + \
+ '" is missing the field "' + \
+ authDelegateKey + \
+ '".'
+ sys.exit(1)
+ else:
+ authDelegateDict = configData[authDelegateKey]
+
+
+# Check if all required keys are parsed.
+requiredKeys = [CLIENT_ID, CLIENT_SECRET, PRODUCT_ID, DEVICE_SERIAL_NUMBER]
+try:
+ missingKey = requiredKeys[map(authDelegateDict.has_key,requiredKeys).index(False)];
+ print 'Missing key: "' + missingKey + '". The list of required keys are:'
+ print ' * ' + '\n * '.join(requiredKeys)
+ print 'Exiting.'
+ sys.exit(1)
+except ValueError:
+ pass
+tokenIsValid=0;
+# Refresh the refresh token to check if it really is a refresh token.
+if authDelegateDict.has_key(REFRESH_TOKEN):
+ postData = {
+ 'grant_type': 'refresh_token',
+ 'refresh_token': authDelegateDict[REFRESH_TOKEN],
+ 'client_id': authDelegateDict[CLIENT_ID],
+ 'client_secret': authDelegateDict[CLIENT_SECRET]}
+ tokenRefreshRequest = requests.post(
+ amazonLwaApiUrl,
+ data=urlencode(postData),
+ headers=amazonLwaApiHeaders)
+ defaultRefreshTokenString = authDelegateDict[REFRESH_TOKEN];
+ if 200 == tokenRefreshRequest.status_code:
+ print 'You have a valid refresh token already in the file.'
+# sys.exit(0)
+ tokenIsValid=1;
+ else:
+ print 'The refresh request failed with the response code ' + \
+ str(tokenRefreshRequest.status_code) + \
+ ('. This might be due to a bad refresh token or bad client data. '
+ 'We will continue with getting a refresh token, discarding the one in the file.\n')
+else:
+ print 'Missing key: "' + REFRESH_TOKEN
+ sys.exit(0)
+# The top page redirects to LWA page.
+
+root="/etc/alexa/web/"
+
+@app.route('/')
+def index():
+ if tokenIsValid:
+ return send_from_directory(root, "logout.html")
+ else:
+ return send_from_directory(root, "splash_screen.html")
+
+
+@app.route("/")
+def getfile(filename):
+ return send_from_directory(root, filename);
+
+@app.route('/logout')
+def logout():
+ copyfile("/etc/alexa/AlexaClientSDKConfigDefault.json", configFilename);
+ return redirect("/splash_screen.html");
+
+@app.route('/login')
+def login():
+ scopeData = ('{{"alexa:all":'
+ '{{"productID":"{productId}",'
+ '"productInstanceAttributes":'
+ '{{"deviceSerialNumber":"{deviceSerialNumber}"}}}}}}').format(
+ productId=authDelegateDict[PRODUCT_ID],
+ deviceSerialNumber=authDelegateDict[DEVICE_SERIAL_NUMBER])
+ lwaUrl = 'https://www.amazon.com/ap/oa/?' + urlencode({
+ 'scope': 'alexa:all',
+ 'scope_data': scopeData,
+ 'client_id': authDelegateDict[CLIENT_ID],
+ 'response_type': 'code',
+ 'redirect_uri': redirectUri,
+ })
+ return redirect(lwaUrl)
+
+
+# The `authresponse` received from the redirect through LWA makes a POST to LWA API to get the token.
+@app.route('/authresponse')
+def get_refresh_token():
+ postData = {
+ 'grant_type': 'authorization_code',
+ 'code': request.args.get('code',''),
+ 'client_id': authDelegateDict[CLIENT_ID],
+ 'client_secret': authDelegateDict[CLIENT_SECRET],
+ 'redirect_uri': redirectUri,
+ }
+ tokenRequest = requests.post(
+ amazonLwaApiUrl,
+ data=urlencode(postData),
+ headers=amazonLwaApiHeaders)
+ if not tokenRequest.json().has_key('refresh_token'):
+ return send_from_directory(root, "authentication_failed.html")
+
+ authDelegateDict['refreshToken'] = tokenRequest.json()['refresh_token']
+ try:
+ configFile = open(configFilename,'r')
+ except IOError:
+ print 'File "' + configFilename + '" cannot be opened!'
+ return '
The file "' + \
+ configFilename + \
+ '" cannot be opened, please check if the file is open elsewhere. ' + \
+ shutdown() + \
+ '