@@ -2,6 +2,8 @@ package httpmw
2
2
3
3
import (
4
4
"context"
5
+ "encoding/base64"
6
+ "encoding/json"
5
7
"fmt"
6
8
"net/http"
7
9
"net/url"
@@ -15,7 +17,6 @@ import (
15
17
"github.com/coder/coder/v2/coderd/httpapi"
16
18
"github.com/coder/coder/v2/coderd/promoauth"
17
19
"github.com/coder/coder/v2/codersdk"
18
- "github.com/coder/coder/v2/cryptorand"
19
20
)
20
21
21
22
type oauth2StateKey struct {}
@@ -84,7 +85,8 @@ func ExtractOAuth2(config promoauth.OAuth2Config, client *http.Client, authURLOp
84
85
return
85
86
}
86
87
87
- code := r .URL .Query ().Get ("code" )
88
+ // code := r.URL.Query().Get("code")
89
+ deviceCode := r .URL .Query ().Get ("device_code" )
88
90
state := r .URL .Query ().Get ("state" )
89
91
redirect := r .URL .Query ().Get ("redirect" )
90
92
if redirect != "" {
@@ -96,76 +98,105 @@ func ExtractOAuth2(config promoauth.OAuth2Config, client *http.Client, authURLOp
96
98
redirect = uriFromURL (redirect )
97
99
}
98
100
99
- if code == "" {
100
- // If the code isn't provided, we'll redirect!
101
- var state string
102
- // If this url param is provided, then a user is trying to merge
103
- // their account with an OIDC account. Their password would have
104
- // been required to get to this point, so we do not need to verify
105
- // their password again.
106
- oidcMergeState := r .URL .Query ().Get ("oidc_merge_state" )
107
- if oidcMergeState != "" {
108
- state = oidcMergeState
109
- } else {
110
- var err error
111
- state , err = cryptorand .String (32 )
112
- if err != nil {
113
- httpapi .Write (ctx , rw , http .StatusInternalServerError , codersdk.Response {
114
- Message : "Internal error generating state string." ,
115
- Detail : err .Error (),
116
- })
117
- return
118
- }
101
+ var da * oauth2.DeviceAuthResponse
102
+ if deviceCode != "" {
103
+ // Decode base64-encoded device code
104
+ decodedBytes , err := base64 .StdEncoding .DecodeString (deviceCode )
105
+ if err != nil {
106
+ httpapi .Write (ctx , rw , http .StatusBadRequest , codersdk.Response {
107
+ Message : "Invalid device code format" ,
108
+ Detail : err .Error (),
109
+ })
110
+ return
119
111
}
120
112
121
- http .SetCookie (rw , & http.Cookie {
122
- Name : codersdk .OAuth2StateCookie ,
123
- Value : state ,
124
- Path : "/" ,
125
- HttpOnly : true ,
126
- SameSite : http .SameSiteLaxMode ,
127
- })
128
- // Redirect must always be specified, otherwise
129
- // an old redirect could apply!
130
- http .SetCookie (rw , & http.Cookie {
131
- Name : codersdk .OAuth2RedirectCookie ,
132
- Value : redirect ,
133
- Path : "/" ,
134
- HttpOnly : true ,
135
- SameSite : http .SameSiteLaxMode ,
136
- })
137
-
138
- http .Redirect (rw , r , config .AuthCodeURL (state , opts ... ), http .StatusTemporaryRedirect )
139
- return
140
- }
141
-
142
- if state == "" {
113
+ // Unmarshal JSON into DeviceAuthResponse
114
+ da = & oauth2.DeviceAuthResponse {}
115
+ if err := json .Unmarshal (decodedBytes , da ); err != nil {
116
+ httpapi .Write (ctx , rw , http .StatusBadRequest , codersdk.Response {
117
+ Message : "Invalid device code data" ,
118
+ Detail : err .Error (),
119
+ })
120
+ return
121
+ }
122
+ } else {
143
123
httpapi .Write (ctx , rw , http .StatusBadRequest , codersdk.Response {
144
- Message : "State must be provided." ,
124
+ Message : "Invalid device code data" ,
125
+ Detail : "Device code is required for device flow." ,
145
126
})
146
127
return
147
128
}
148
129
149
- stateCookie , err := r .Cookie (codersdk .OAuth2StateCookie )
150
- if err != nil {
151
- httpapi .Write (ctx , rw , http .StatusUnauthorized , codersdk.Response {
152
- Message : fmt .Sprintf ("Cookie %q must be provided." , codersdk .OAuth2StateCookie ),
153
- })
154
- return
155
- }
156
- if stateCookie .Value != state {
157
- httpapi .Write (ctx , rw , http .StatusUnauthorized , codersdk.Response {
158
- Message : "State mismatched." ,
159
- })
160
- return
161
- }
130
+ // if code == "" {
131
+ // // If the code isn't provided, we'll redirect!
132
+ // var state string
133
+ // // If this url param is provided, then a user is trying to merge
134
+ // // their account with an OIDC account. Their password would have
135
+ // // been required to get to this point, so we do not need to verify
136
+ // // their password again.
137
+ // oidcMergeState := r.URL.Query().Get("oidc_merge_state")
138
+ // if oidcMergeState != "" {
139
+ // state = oidcMergeState
140
+ // } else {
141
+ // var err error
142
+ // state, err = cryptorand.String(32)
143
+ // if err != nil {
144
+ // httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
145
+ // Message: "Internal error generating state string.",
146
+ // Detail: err.Error(),
147
+ // })
148
+ // return
149
+ // }
150
+ // }
151
+
152
+ http .SetCookie (rw , & http.Cookie {
153
+ Name : codersdk .OAuth2StateCookie ,
154
+ Value : "hello" ,
155
+ Path : "/" ,
156
+ HttpOnly : true ,
157
+ SameSite : http .SameSiteLaxMode ,
158
+ })
159
+ // // Redirect must always be specified, otherwise
160
+ // // an old redirect could apply!
161
+ // http.SetCookie(rw, &http.Cookie{
162
+ // Name: codersdk.OAuth2RedirectCookie,
163
+ // Value: redirect,
164
+ // Path: "/",
165
+ // HttpOnly: true,
166
+ // SameSite: http.SameSiteLaxMode,
167
+ // })
168
+
169
+ // http.Redirect(rw, r, config.AuthCodeURL(state, opts...), http.StatusTemporaryRedirect)
170
+ // return
171
+ // }
172
+
173
+ // if state == "" {
174
+ // httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
175
+ // Message: "State must be provided.",
176
+ // })
177
+ // return
178
+ // }
179
+
180
+ // stateCookie, err := r.Cookie(codersdk.OAuth2StateCookie)
181
+ // if err != nil {
182
+ // httpapi.Write(ctx, rw, http.StatusUnauthorized, codersdk.Response{
183
+ // Message: fmt.Sprintf("Cookie %q must be provided.", codersdk.OAuth2StateCookie),
184
+ // })
185
+ // return
186
+ // }
187
+ // if stateCookie.Value != state {
188
+ // httpapi.Write(ctx, rw, http.StatusUnauthorized, codersdk.Response{
189
+ // Message: "State mismatched.",
190
+ // })
191
+ // return
192
+ // }
162
193
163
194
stateRedirect , err := r .Cookie (codersdk .OAuth2RedirectCookie )
164
195
if err == nil {
165
196
redirect = stateRedirect .Value
166
197
}
167
198
168
- oauthToken , err := config .Exchange (ctx , code )
199
+ oauthToken , err := config .DeviceAccessToken (ctx , da )
169
200
if err != nil {
170
201
httpapi .Write (ctx , rw , http .StatusInternalServerError , codersdk.Response {
171
202
Message : "Internal error exchanging Oauth code." ,
0 commit comments