@@ -4,10 +4,14 @@ This is an example application to demonstrate parsing an ID Token.
4
4
package main
5
5
6
6
import (
7
+ "crypto/rand"
8
+ "encoding/base64"
7
9
"encoding/json"
10
+ "io"
8
11
"log"
9
12
"net/http"
10
13
"os"
14
+ "time"
11
15
12
16
"github.com/coreos/go-oidc/v3/oidc"
13
17
"golang.org/x/net/context"
19
23
clientSecret = os .Getenv ("GOOGLE_OAUTH2_CLIENT_SECRET" )
20
24
)
21
25
26
+ func randString (nByte int ) (string , error ) {
27
+ b := make ([]byte , nByte )
28
+ if _ , err := io .ReadFull (rand .Reader , b ); err != nil {
29
+ return "" , err
30
+ }
31
+ return base64 .RawURLEncoding .EncodeToString (b ), nil
32
+ }
33
+
34
+ func setCallbackCookie (w http.ResponseWriter , r * http.Request , name , value string ) {
35
+ c := & http.Cookie {
36
+ Name : name ,
37
+ Value : value ,
38
+ MaxAge : int (time .Hour .Seconds ()),
39
+ Secure : r .TLS != nil ,
40
+ HttpOnly : true ,
41
+ }
42
+ http .SetCookie (w , c )
43
+ }
44
+
22
45
func main () {
23
46
ctx := context .Background ()
24
47
@@ -39,14 +62,30 @@ func main() {
39
62
Scopes : []string {oidc .ScopeOpenID , "profile" , "email" },
40
63
}
41
64
42
- state := "foobar" // Don't do this in production.
43
-
44
65
http .HandleFunc ("/" , func (w http.ResponseWriter , r * http.Request ) {
45
- http .Redirect (w , r , config .AuthCodeURL (state ), http .StatusFound )
66
+ state , err := randString (16 )
67
+ if err != nil {
68
+ http .Error (w , "Internal error" , http .StatusInternalServerError )
69
+ return
70
+ }
71
+ nonce , err := randString (16 )
72
+ if err != nil {
73
+ http .Error (w , "Internal error" , http .StatusInternalServerError )
74
+ return
75
+ }
76
+ setCallbackCookie (w , r , "state" , state )
77
+ setCallbackCookie (w , r , "nonce" , nonce )
78
+
79
+ http .Redirect (w , r , config .AuthCodeURL (state , oidc .Nonce (nonce )), http .StatusFound )
46
80
})
47
81
48
82
http .HandleFunc ("/auth/google/callback" , func (w http.ResponseWriter , r * http.Request ) {
49
- if r .URL .Query ().Get ("state" ) != state {
83
+ state , err := r .Cookie ("state" )
84
+ if err != nil {
85
+ http .Error (w , "state not found" , http .StatusBadRequest )
86
+ return
87
+ }
88
+ if r .URL .Query ().Get ("state" ) != state .Value {
50
89
http .Error (w , "state did not match" , http .StatusBadRequest )
51
90
return
52
91
}
@@ -67,6 +106,16 @@ func main() {
67
106
return
68
107
}
69
108
109
+ nonce , err := r .Cookie ("nonce" )
110
+ if err != nil {
111
+ http .Error (w , "nonce not found" , http .StatusBadRequest )
112
+ return
113
+ }
114
+ if idToken .Nonce != nonce .Value {
115
+ http .Error (w , "nonce did not match" , http .StatusBadRequest )
116
+ return
117
+ }
118
+
70
119
oauth2Token .AccessToken = "*REDACTED*"
71
120
72
121
resp := struct {
0 commit comments