Last active
December 8, 2021 07:05
-
-
Save audrenbdb/a1bca04ac459e6fa6580c5953de35ece to your computer and use it in GitHub Desktop.
Minimum OAuth2 local client
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
<!DOCTYPE html> | |
<html> | |
<body> | |
<a | |
href="http://localhost:9096/oauth/authorize?client_id=paulthebest&redirect_uri=http://localhost:8080/oauth/redirect&response_type=code"> | |
Login | |
</a> | |
</body> | |
</html> |
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" | |
"fmt" | |
"io" | |
"log" | |
"net/http" | |
"os" | |
) | |
const clientID = "paulthebest" | |
func main() { | |
fs := http.FileServer(http.Dir("public")) | |
http.Handle("/", fs) | |
// We will be using `httpClient` to make external HTTP requests later in our code | |
httpClient := http.Client{} | |
// Create a new redirect route route | |
http.HandleFunc("/oauth/redirect", func(w http.ResponseWriter, r *http.Request) { | |
// First, we need to get the value of the `code` query param | |
err := r.ParseForm() | |
if err != nil { | |
fmt.Fprintf(os.Stdout, "could not parse query: %v", err) | |
w.WriteHeader(http.StatusBadRequest) | |
} | |
code := r.Form.Get("code") | |
reqURL := fmt.Sprintf("http://localhost:9096/oauth/token?client_id=%s&code=%s&grant_type=authorization_code&redirect_uri=http://localhost:8080/oauth/redirect", clientID, code) | |
req, err := http.NewRequest(http.MethodPost, reqURL, nil) | |
if err != nil { | |
fmt.Fprintf(os.Stdout, "could not create HTTP request: %v", err) | |
w.WriteHeader(http.StatusBadRequest) | |
} | |
// We set this header since we want the response | |
// as JSON | |
req.Header.Set("accept", "application/json") | |
// Send out the HTTP request | |
res, err := httpClient.Do(req) | |
if err != nil { | |
fmt.Fprintf(os.Stdout, "could not send HTTP request: %v", err) | |
w.WriteHeader(http.StatusInternalServerError) | |
} | |
defer res.Body.Close() | |
// Parse the request body into the `OAuthAccessResponse` struct | |
var t OAuthAccessResponse | |
b, err := io.ReadAll(res.Body) | |
err = json.Unmarshal(b, &t) | |
if err != nil { | |
log.Printf("error decoding sakura response: %v", err) | |
if e, ok := err.(*json.SyntaxError); ok { | |
log.Printf("syntax error at byte offset %d", e.Offset) | |
} | |
log.Printf("sakura response: %q", res.Body) | |
} | |
// Finally, send a response to redirect the user to the "welcome" page | |
// with the access token | |
w.Header().Set("Location", "/welcome.html?access_token="+t.AccessToken) | |
w.WriteHeader(http.StatusFound) | |
}) | |
http.ListenAndServe(":8080", nil) | |
} | |
type OAuthAccessResponse struct { | |
AccessToken string `json:"access_token"` | |
} |
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
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="UTF-8" /> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> | |
<meta http-equiv="X-UA-Compatible" content="ie=edge" /> | |
<title>Hello</title> | |
</head> | |
<body></body> | |
<script> | |
// We can get the token from the "access_token" query | |
// param, available in the browsers "location" global | |
const query = window.location.search.substring(1); | |
const token = query.split("access_token=")[1]; | |
// Call the user info API using the fetch browser library | |
fetch("http://localhost:9096/user", { | |
headers: { | |
Accept: "application/json", | |
Authorization: "Bearer " + token, | |
}, | |
}) | |
// Parse the response as JSON | |
.then((res) => res.json()) | |
.then((res) => { | |
const nameNode = document.createTextNode(`Welcome, ${res.first_name} ${res.last_name}`) | |
document.body.appendChild(nameNode); | |
}); | |
</script> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment