-
-
Save tcnksm/3ca4ad1709da91386c9173ff0d926aa8 to your computer and use it in GitHub Desktop.
Amazon Alexa Simple Account Linking Server by Golang
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"encoding/json" | |
"log" | |
"net/http" | |
"os" | |
"time" | |
"golang.org/x/oauth2" | |
) | |
const ( | |
DefaultPort = "3000" | |
) | |
func main() { | |
http.HandleFunc("/auth", authHandler) | |
http.HandleFunc("/token", tokenHandler) | |
port := DefaultPort | |
if v := os.Getenv("PORT"); len(v) != 0 { | |
port = v | |
} | |
log.Printf("[INFO] Start listening on %s", port) | |
if err := http.ListenAndServe(":"+port, nil); err != nil { | |
log.Printf("[ERROR] %s", err) | |
} | |
} | |
func authHandler(w http.ResponseWriter, r *http.Request) { | |
username, password, ok := r.BasicAuth() | |
if !ok || !(username == AlexaAdminName && password == AlexaAdminPass) { | |
w.Header().Set("WWW-Authenticate", `Basic realm="alexa-auth"`) | |
w.WriteHeader(http.StatusUnauthorized) | |
w.Write([]byte("Unauthorized")) | |
return | |
} | |
if v := r.FormValue("client_id"); v != ClientID { | |
log.Printf("[ERROR] Invalid client_id: %q", v) | |
w.WriteHeader(http.StatusInternalServerError) | |
w.Write([]byte("error")) | |
return | |
} | |
if v := r.FormValue("response_type"); v != "code" { | |
w.WriteHeader(http.StatusBadRequest) | |
w.Write([]byte("Bad request\n")) | |
return | |
} | |
state := r.FormValue("state") | |
if len(state) == 0 { | |
w.WriteHeader(http.StatusBadRequest) | |
w.Write([]byte("Bad request\n")) | |
return | |
} | |
req, err := http.NewRequest("GET", RedirectURL, nil) | |
if err != nil { | |
log.Printf("[ERROR] %s", err) | |
w.WriteHeader(http.StatusInternalServerError) | |
w.Write([]byte("Internal Server Error\n")) | |
return | |
} | |
values := req.URL.Query() | |
values.Add("state", state) | |
values.Add("code", AuthorizationCode) | |
req.URL.RawQuery = values.Encode() | |
log.Printf("[INFO] location: %s", req.URL.String()) | |
http.Redirect(w, r, req.URL.String(), http.StatusFound) | |
} | |
func tokenHandler(w http.ResponseWriter, r *http.Request) { | |
username, password, ok := r.BasicAuth() | |
if !ok || !(username == ClientID && password == ClientSecret) { | |
w.Header().Set("WWW-Authenticate", `Basic realm="alexa-token"`) | |
w.WriteHeader(http.StatusUnauthorized) | |
w.Write([]byte("Unauthorized")) | |
return | |
} | |
if v := r.FormValue("grant_type"); v != "authorization_code" { | |
log.Printf("[ERROR] Invalid grant_type: %s", v) | |
w.WriteHeader(http.StatusBadRequest) | |
w.Write([]byte("Bad request\n")) | |
return | |
} | |
if v := r.FormValue("code"); v != AuthorizationCode { | |
log.Printf("[ERROR] Invalid code: %s", v) | |
w.WriteHeader(http.StatusBadRequest) | |
w.Write([]byte("Bad request\n")) | |
return | |
} | |
token := oauth2.Token{ | |
AccessToken: AccessToken, | |
RefreshToken: AccessToken, | |
TokenType: "Bearer", | |
Expiry: time.Now().Add(30 * 24 * time.Hour), | |
} | |
buf, err := json.Marshal(&token) | |
if err != nil { | |
log.Printf("[ERROR] Marshal: %s", err) | |
w.WriteHeader(http.StatusInternalServerError) | |
w.Write([]byte("error")) | |
return | |
} | |
w.Header().Add("Content-Type", "application/json") | |
w.WriteHeader(http.StatusOK) | |
w.Write(buf) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
hi, thanks for posting this code. can I use port 3000 in production? or do I have to use port 443 ?