Skip to content

Instantly share code, notes, and snippets.

@BellringerQuinn
Last active June 3, 2024 14:21
Show Gist options
  • Select an option

  • Save BellringerQuinn/d012cd29eb9e756fe3555d4d03b001b2 to your computer and use it in GitHub Desktop.

Select an option

Save BellringerQuinn/d012cd29eb9e756fe3555d4d03b001b2 to your computer and use it in GitHub Desktop.
wallet_oauth - editor social sign in
package main
import (
"encoding/json"
"fmt"
"net/http"
"strings"
)
var schemeMap = make(map[string]string)
func waasOAuthCallback(w http.ResponseWriter, r *http.Request) {
var idToken, state string
if contentType := r.Header.Get("Content-Type"); strings.Contains(contentType, "application/x-www-form-urlencoded") { // Apple requires this response format. See https://developer.apple.com/documentation/sign_in_with_apple/sign_in_with_apple_js/incorporating_sign_in_with_apple_into_other_platforms#3332113. Note: while the docs, at time of writing, mention that 'fragment' is also a supported response type, testing reveals that it is not.
if err := r.ParseForm(); err != nil {
http.Error(w, "Failed to parse form", http.StatusBadRequest)
return
}
idToken = r.Form.Get("id_token")
state = r.Form.Get("state")
urlScheme := strings.Split(state, "---")[0]
if urlScheme == "unity-editor" {
forwardRedirectToDatabase(w, r, state, idToken)
return
}
if idToken != "" && state != "" {
sendCustomUrlScheme(idToken, state, w)
} else {
http.Error(w, "id_token or state not found in request", http.StatusBadRequest)
}
} else {
handleViaJavascript(w)
return
}
}
func forwardRedirectToDatabase(w http.ResponseWriter, r *http.Request, state, idToken string) {
schemeMap[state] = r.URL.String() + "#state=" + state + "&id_token=" + idToken
w.Header().Set("Content-Type", "text/plain")
fmt.Fprint(w, "Success")
}
func sendCustomUrlScheme(idToken, state string, w http.ResponseWriter) {
urlScheme := strings.Split(state, "---")[0]
customURLScheme := fmt.Sprintf("%s://oauth2callback#?id_token=%s&state=%s", urlScheme, idToken, state)
// Send a response with a script to redirect the user
jsCode := fmt.Sprintf(`
<html>
<head>
<title>...</title>
</head>
<script>
window.location.href = %s;
document.body.innerHTML = '<h1 id="returnMessage"><a href="' + %s + '">Click to return to app</a></h1>';
document.getElementById("returnMessage").addEventListener("click", function() {
document.body.innerHTML = '<h1>Please close this page and return to app</h1>';
});
</script>
</html>
`, customURLScheme, customURLScheme)
w.Header().Set("Content-Type", "text/html")
fmt.Fprint(w, jsCode)
}
func handleViaJavascript(w http.ResponseWriter) {
jsCode := `<html>
<head>
<title>...</title>
</head>
<script>
function parseUrlParams() {
var hash = window.location.hash.substr(1);
var hashParams = hash.split('&');
var idToken, state;
for (var i = 0; i < hashParams.length; i++) {
var p = hashParams[i].split('=');
switch (p[0]) {
case 'id_token':
idToken = p[1];
break;
case 'state':
state = p[1];
break;
}
}
if (idToken && state) {
sendCustomUrlScheme(idToken, state);
} else {
console.error('id_token or state not found in URL hash fragment');
}
}
function sendCustomUrlScheme(idToken, state) {
var urlScheme = state.split('---')[0];
var customURLScheme = urlScheme + '://oauth2callback#?id_token=' + idToken + '&state=' + state;
if (urlScheme === 'unity-editor') {
fetch('/storeRedirectUrl', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ redirectUrl: window.location.href, state: state }),
})
.then(response => {
if (response.ok) {
console.log('Redirect URL stored successfully.');
document.body.innerHTML = '<h1>Please close this page and return to Unity</h1>';
window.close();
} else {
console.error('Failed to store redirect URL.');
}
})
.catch(error => {
console.error('Error storing redirect URL:', error);
});
return;
}
window.location.href = customURLScheme;
document.body.innerHTML = '<h1 id="returnMessage"><a href="' + customURLScheme + '">Click to return to app</a></h1>';
document.getElementById("returnMessage").addEventListener("click", function() {
document.body.innerHTML = '<h1>Please close this page and return to app</h1>';
});
}
window.onload = parseUrlParams;
</script>
</html>`
w.Header().Set("Content-Type", "text/html")
fmt.Fprint(w, jsCode)
}
func storeRedirectUrlHandler(w http.ResponseWriter, r *http.Request) {
var data struct {
RedirectUrl string `json:"redirectUrl"`
State string `json:"state"`
}
if err := json.NewDecoder(r.Body).Decode(&data); err != nil {
http.Error(w, "Failed to decode JSON", http.StatusBadRequest)
return
}
data.State = strings.TrimSuffix(data.State, "/")
schemeMap[data.State] = data.RedirectUrl
w.WriteHeader(http.StatusOK)
}
func getResult(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", "*")
state := r.URL.Query().Get("state")
urlScheme, ok := schemeMap[state]
if !ok {
w.Header().Set("Content-Type", "text/plain")
fmt.Fprint(w, "")
return
}
delete(schemeMap, state)
w.Header().Set("Content-Type", "text/plain")
fmt.Fprintf(w, "%s", urlScheme)
}
func main() {
http.HandleFunc("/", waasOAuthCallback)
http.HandleFunc("/getResult", getResult)
http.HandleFunc("/storeRedirectUrl", storeRedirectUrlHandler)
fmt.Println("Server listening on port 8080")
http.ListenAndServe(":8080", nil)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment