auth
auth/request.go
Implement an endpoint for token information. Implement an endpoint that allows us to look up information on a token. We strip the refresh token before the response is sent to avoid leaking the response token.
1 package auth
3 import (
4 "encoding/json"
5 "log"
6 "net/http"
8 "bitbucket.org/ww/goautoneg"
9 )
11 const (
12 requestErrAccessDenied = "access_denied"
13 requestErrInsufficient = "insufficient"
14 requestErrOverflow = "overflow"
15 requestErrInvalidValue = "invalid_value"
16 requestErrInvalidFormat = "invalid_format"
17 requestErrMissing = "missing"
18 requestErrNotFound = "not_found"
19 requestErrConflict = "conflict"
20 requestErrActOfGod = "act_of_god"
21 )
23 var (
24 actOfGodResponse = response{Errors: []requestError{requestError{Slug: requestErrActOfGod}}}
25 invalidFormatResponse = response{Errors: []requestError{requestError{Slug: requestErrInvalidFormat, Field: "/"}}}
27 encoders = []string{"application/json"}
28 )
30 type response struct {
31 Errors []requestError `json:"errors,omitempty"`
32 Logins []Login `json:"logins,omitempty"`
33 Profiles []Profile `json:"profiles,omitempty"`
34 Clients []Client `json:"clients,omitempty"`
35 Endpoints []Endpoint `json:"endpoints,omitempty"`
36 Sessions []Session `json:"sessions,omitempty"`
37 Tokens []Token `json:"tokens,omitempty"`
38 }
40 type requestError struct {
41 Slug string `json:"error,omitempty"`
42 Field string `json:"field,omitempty"`
43 Param string `json:"param,omitempty"`
44 Header string `json:"header,omitempty"`
45 }
47 func negotiate(h http.Handler) http.Handler {
48 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
49 if r.Header.Get("Accept") != "" {
50 contentType := goautoneg.Negotiate(r.Header.Get("Accept"), encoders)
51 if contentType == "" {
52 w.WriteHeader(http.StatusNotAcceptable)
53 w.Write([]byte("Unsupported content type requested: " + r.Header.Get("Accept")))
54 return
55 }
56 }
57 h.ServeHTTP(w, r)
58 })
59 }
61 func encode(w http.ResponseWriter, r *http.Request, status int, resp response) {
62 contentType := goautoneg.Negotiate(r.Header.Get("Accept"), encoders)
63 w.Header().Set("content-type", contentType)
64 w.WriteHeader(status)
65 var err error
66 switch contentType {
67 case "application/json":
68 enc := json.NewEncoder(w)
69 err = enc.Encode(resp)
70 default:
71 enc := json.NewEncoder(w)
72 err = enc.Encode(resp)
73 }
74 if err != nil {
75 log.Println(err)
76 }
77 }
79 func decode(r *http.Request, target interface{}) error {
80 defer r.Body.Close()
81 switch r.Header.Get("Content-Type") {
82 case "application/json":
83 dec := json.NewDecoder(r.Body)
84 return dec.Decode(target)
85 default:
86 dec := json.NewDecoder(r.Body)
87 return dec.Decode(target)
88 }
89 }
91 func wrap(context Context, f func(w http.ResponseWriter, r *http.Request, context Context)) http.Handler {
92 return negotiate(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
93 w.Header().Set("Access-Control-Allow-Origin", "*")
94 w.Header().Set("Access-Control-Allow-Headers", r.Header.Get("Access-Control-Request-Headers"))
95 w.Header().Set("Access-Control-Allow-Credentials", "true")
96 if r.Method == "OPTIONS" {
97 w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, PATCH, OPTIONS")
98 w.Header().Set("Allow", "GET, POST, PUT, DELETE, PATCH, OPTIONS")
99 w.WriteHeader(http.StatusOK)
100 return
101 }
102 f(w, r, context)
103 }))
104 }