handler renders the callback endpoint. It reports the outcome exactly once and always shows the user a friendly page.
(expectedState string)
| 79 | // handler renders the callback endpoint. It reports the outcome exactly once and |
| 80 | // always shows the user a friendly page. |
| 81 | func (cs *callbackServer) handler(expectedState string) http.Handler { |
| 82 | mux := http.NewServeMux() |
| 83 | mux.HandleFunc("/callback", func(w http.ResponseWriter, r *http.Request) { |
| 84 | q := r.URL.Query() |
| 85 | |
| 86 | if errCode := q.Get("error"); errCode != "" { |
| 87 | msg := errCode |
| 88 | if desc := q.Get("error_description"); desc != "" { |
| 89 | msg = fmt.Sprintf("%s: %s", errCode, desc) |
| 90 | } |
| 91 | cs.report(callbackResult{err: fmt.Errorf("authorization failed: %s", msg)}) |
| 92 | renderError(w, msg) |
| 93 | return |
| 94 | } |
| 95 | |
| 96 | if q.Get("state") != expectedState { |
| 97 | cs.report(callbackResult{err: fmt.Errorf("state mismatch (possible CSRF)")}) |
| 98 | renderError(w, "state mismatch") |
| 99 | return |
| 100 | } |
| 101 | |
| 102 | code := q.Get("code") |
| 103 | if code == "" { |
| 104 | cs.report(callbackResult{err: fmt.Errorf("no authorization code in callback")}) |
| 105 | renderError(w, "no authorization code received") |
| 106 | return |
| 107 | } |
| 108 | |
| 109 | cs.report(callbackResult{code: code}) |
| 110 | renderSuccess(w) |
| 111 | }) |
| 112 | return mux |
| 113 | } |
| 114 | |
| 115 | // report delivers the first outcome and drops later ones (the channel is |
| 116 | // buffered for one; subsequent redirect retries must not block the handler). |