Signed-off-by: brookjeynes me@brookjeynes.dev
+2
internal/server/handlers/login.go
+2
internal/server/handlers/login.go
···
19
switch r.Method {
20
case http.MethodGet:
21
returnURL := r.URL.Query().Get("return_url")
22
+
errorCode := r.URL.Query().Get("error")
23
views.LoginPage(views.LoginPageParams{
24
ReturnUrl: returnURL,
25
+
ErrorCode: errorCode,
26
}).Render(r.Context(), w)
27
case http.MethodPost:
28
handle := r.FormValue("handle")
+15
-8
internal/server/oauth/handler.go
+15
-8
internal/server/oauth/handler.go
···
3
import (
4
"context"
5
"encoding/json"
6
"fmt"
7
"net/http"
8
"time"
9
10
comatproto "github.com/bluesky-social/indigo/api/atproto"
11
lexutil "github.com/bluesky-social/indigo/lex/util"
12
"github.com/go-chi/chi/v5"
13
"github.com/lestrrat-go/jwx/v2/jwk"
···
16
"yoten.app/api/yoten"
17
ph "yoten.app/internal/clients/posthog"
18
"yoten.app/internal/db"
19
-
"yoten.app/internal/server/htmx"
20
)
21
22
func (o *OAuth) Router() http.Handler {
···
71
}
72
73
func (o *OAuth) callback(w http.ResponseWriter, r *http.Request) {
74
-
l := o.Logger.With("handler", "callback")
75
ctx := r.Context()
76
77
sessData, err := o.ClientApp.ProcessCallback(ctx, r.URL.Query())
78
if err != nil {
79
-
o.Logger.Error("failed to process callback", "err", err)
80
-
http.Error(w, err.Error(), http.StatusInternalServerError)
81
return
82
}
83
84
if err := o.SaveSession(w, r, sessData); err != nil {
85
l.Error("failed to save session", "err", err)
86
-
http.Error(w, err.Error(), http.StatusInternalServerError)
87
return
88
}
89
···
91
resolved, err := o.IdResolver.ResolveIdent(context.Background(), did)
92
if err != nil {
93
l.Error("failed to resolve handle", "handle", resolved.Handle.String(), "err", err)
94
-
htmx.HxError(w, http.StatusBadRequest, fmt.Sprintf("'%s' is an invalid handle", resolved.Handle.String()))
95
return
96
}
97
98
client, err := o.AuthorizedClient(r)
99
if err != nil {
100
l.Error("failed to get authorized client", "err", err)
101
-
http.Error(w, err.Error(), http.StatusInternalServerError)
102
return
103
}
104
···
128
})
129
if err != nil {
130
l.Error("failed to create profile record", "err", err)
131
-
htmx.HxError(w, http.StatusInternalServerError, "Failed to announce profile creation, try again later")
132
return
133
}
134
···
3
import (
4
"context"
5
"encoding/json"
6
+
"errors"
7
"fmt"
8
"net/http"
9
"time"
10
11
comatproto "github.com/bluesky-social/indigo/api/atproto"
12
+
"github.com/bluesky-social/indigo/atproto/auth/oauth"
13
lexutil "github.com/bluesky-social/indigo/lex/util"
14
"github.com/go-chi/chi/v5"
15
"github.com/lestrrat-go/jwx/v2/jwk"
···
18
"yoten.app/api/yoten"
19
ph "yoten.app/internal/clients/posthog"
20
"yoten.app/internal/db"
21
)
22
23
func (o *OAuth) Router() http.Handler {
···
72
}
73
74
func (o *OAuth) callback(w http.ResponseWriter, r *http.Request) {
75
ctx := r.Context()
76
+
l := o.Logger.With("handler", "callback").With("query", r.URL.Query())
77
78
sessData, err := o.ClientApp.ProcessCallback(ctx, r.URL.Query())
79
if err != nil {
80
+
var callbackErr *oauth.AuthRequestCallbackError
81
+
if errors.As(err, &callbackErr) {
82
+
l.Debug("callback error", "err", callbackErr)
83
+
http.Redirect(w, r, fmt.Sprintf("/login?error=%s", callbackErr.ErrorCode), http.StatusFound)
84
+
return
85
+
}
86
+
l.Error("failed to process callback", "err", err)
87
+
http.Redirect(w, r, "/login?error=oauth", http.StatusFound)
88
return
89
}
90
91
if err := o.SaveSession(w, r, sessData); err != nil {
92
l.Error("failed to save session", "err", err)
93
+
http.Redirect(w, r, "/login?error=session", http.StatusFound)
94
return
95
}
96
···
98
resolved, err := o.IdResolver.ResolveIdent(context.Background(), did)
99
if err != nil {
100
l.Error("failed to resolve handle", "handle", resolved.Handle.String(), "err", err)
101
+
http.Redirect(w, r, "/login?error=handle", http.StatusFound)
102
return
103
}
104
105
client, err := o.AuthorizedClient(r)
106
if err != nil {
107
l.Error("failed to get authorized client", "err", err)
108
+
http.Redirect(w, r, "/login?error=client", http.StatusFound)
109
return
110
}
111
···
135
})
136
if err != nil {
137
l.Error("failed to create profile record", "err", err)
138
+
http.Redirect(w, r, "/login?error=profile-creation", http.StatusFound)
139
return
140
}
141
+23
internal/server/views/login.templ
+23
internal/server/views/login.templ
···
44
<i class="w-4 h-4" data-lucide="arrow-right"></i>
45
</button>
46
</form>
47
+
if params.ErrorCode != "" {
48
+
<div class="flex flex-col my-4 p-4 bg-red-50 border border-red-500 rounded-lg text-red-500">
49
+
<div class="flex items-center gap-1">
50
+
<i class="w-4 h-4" data-lucide="circle-alert"></i>
51
+
<h5 class="font-medium">Login error</h5>
52
+
</div>
53
+
<div>
54
+
<p class="text-sm">
55
+
switch (params.ErrorCode) {
56
+
case "access_denied":
57
+
You have not authorized the app.
58
+
case "session":
59
+
Server failed to create user session.
60
+
case "handle":
61
+
Server failed to validate your handle.
62
+
default:
63
+
Internal Server error.
64
+
}
65
+
Please try again.
66
+
</p>
67
+
</div>
68
+
</div>
69
+
}
70
<div class="mt-6 pt-6 border-t border-bg-dark">
71
<div class="text-center">
72
<p class="text-sm text-text-muted mb-3">New to the AT Protocol?</p>
History
1 round
0 comments
brookjeynes.dev
submitted
#0
1 commit
expand
collapse
feat(oauth/handler): pass error codes back to login page
Signed-off-by: brookjeynes <me@brookjeynes.dev>
expand 0 comments
pull request successfully merged