appview/oauth: handle failed login with error code #717

merged
opened by boltless.me targeting master from push-zmowtwoprttl
Changed files
+35 -4
appview
oauth
pages
templates
user
state
+13 -2
appview/oauth/handler.go
···
"bytes"
"context"
"encoding/json"
+
"errors"
"fmt"
"net/http"
"slices"
"time"
+
"github.com/bluesky-social/indigo/atproto/auth/oauth"
"github.com/go-chi/chi/v5"
"github.com/lestrrat-go/jwx/v2/jwk"
"github.com/posthog/posthog-go"
···
func (o *OAuth) callback(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
+
l := o.Logger.With("query", r.URL.Query())
sessData, err := o.ClientApp.ProcessCallback(ctx, r.URL.Query())
if err != nil {
-
http.Error(w, err.Error(), http.StatusInternalServerError)
+
var callbackErr *oauth.AuthRequestCallbackError
+
if errors.As(err, &callbackErr) {
+
l.Debug("callback error", "err", callbackErr)
+
http.Redirect(w, r, fmt.Sprintf("/login?error=%s", callbackErr.ErrorCode), http.StatusFound)
+
return
+
}
+
l.Error("failed to process callback", "err", err)
+
http.Redirect(w, r, "/login?error=oauth", http.StatusFound)
return
}
if err := o.SaveSession(w, r, sessData); err != nil {
-
http.Error(w, err.Error(), http.StatusInternalServerError)
+
l.Error("failed to save session", "data", sessData, "err", err)
+
http.Redirect(w, r, "/login?error=session", http.StatusFound)
return
}
+1
appview/pages/pages.go
···
type LoginParams struct {
ReturnUrl string
+
ErrorCode string
}
func (p *Pages) Login(w io.Writer, params LoginParams) error {
+19 -2
appview/pages/templates/user/login.html
···
<title>login &middot; tangled</title>
</head>
<body class="flex items-center justify-center min-h-screen">
-
<main class="max-w-md px-6 -mt-4">
+
<main class="max-w-md px-7 mt-4">
<h1 class="flex place-content-center text-3xl font-semibold italic dark:text-white" >
{{ template "fragments/logotype" }}
</h1>
···
tightly-knit social coding.
</h2>
<form
-
class="mt-4 max-w-sm mx-auto"
+
class="mt-4"
hx-post="/login"
hx-swap="none"
hx-disabled-elt="#login-button"
···
<span>login</span>
</button>
</form>
+
{{ if .ErrorCode }}
+
<div class="flex gap-2 my-2 bg-red-50 dark:bg-red-900 border border-red-500 rounded drop-shadow-sm px-3 py-2 text-red-500 dark:text-red-300">
+
<span class="py-1">{{ i "circle-alert" "w-4 h-4" }}</span>
+
<div>
+
<h5 class="font-medium">Login error</h5>
+
<p class="text-sm">
+
{{ if eq .ErrorCode "access_denied" }}
+
You have not authorized the app. Please try again
+
{{ else if eq .ErrorCode "session" }}
+
Server failed to create user session. Please try again
+
{{ else }}
+
Internal Server error. Please try again
+
</p>
+
{{ end }}
+
</div>
+
</div>
+
{{ end }}
<p class="text-sm text-gray-500">
Don't have an account? <a href="/signup" class="underline">Create an account</a> on Tangled now!
</p>
+2
appview/state/login.go
···
switch r.Method {
case http.MethodGet:
returnURL := r.URL.Query().Get("return_url")
+
errorCode := r.URL.Query().Get("error")
s.pages.Login(w, pages.LoginParams{
ReturnUrl: returnURL,
+
ErrorCode: errorCode,
})
case http.MethodPost:
handle := r.FormValue("handle")