...

Source file src/github.com/golang-jwt/jwt/http_example_test.go

Documentation: github.com/golang-jwt/jwt

     1  package jwt_test
     2  
     3  // Example HTTP auth using asymmetric crypto/RSA keys
     4  // This is based on a (now outdated) example at https://gist.github.com/cryptix/45c33ecf0ae54828e63b
     5  
     6  import (
     7  	"bytes"
     8  	"crypto/rsa"
     9  	"fmt"
    10  	"io"
    11  	"io/ioutil"
    12  	"log"
    13  	"net"
    14  	"net/http"
    15  	"net/url"
    16  	"strings"
    17  	"time"
    18  
    19  	"github.com/golang-jwt/jwt"
    20  	"github.com/golang-jwt/jwt/request"
    21  )
    22  
    23  // location of the files used for signing and verification
    24  const (
    25  	privKeyPath = "test/sample_key"     // openssl genrsa -out app.rsa keysize
    26  	pubKeyPath  = "test/sample_key.pub" // openssl rsa -in app.rsa -pubout > app.rsa.pub
    27  )
    28  
    29  var (
    30  	verifyKey  *rsa.PublicKey
    31  	signKey    *rsa.PrivateKey
    32  	serverPort int
    33  	// storing sample username/password pairs
    34  	// don't do this on a real server
    35  	users = map[string]string{
    36  		"test": "known",
    37  	}
    38  )
    39  
    40  // read the key files before starting http handlers
    41  func init() {
    42  	signBytes, err := ioutil.ReadFile(privKeyPath)
    43  	fatal(err)
    44  
    45  	signKey, err = jwt.ParseRSAPrivateKeyFromPEM(signBytes)
    46  	fatal(err)
    47  
    48  	verifyBytes, err := ioutil.ReadFile(pubKeyPath)
    49  	fatal(err)
    50  
    51  	verifyKey, err = jwt.ParseRSAPublicKeyFromPEM(verifyBytes)
    52  	fatal(err)
    53  
    54  	http.HandleFunc("/authenticate", authHandler)
    55  	http.HandleFunc("/restricted", restrictedHandler)
    56  
    57  	// Setup listener
    58  	listener, err := net.ListenTCP("tcp", &net.TCPAddr{})
    59  	fatal(err)
    60  	serverPort = listener.Addr().(*net.TCPAddr).Port
    61  
    62  	log.Println("Listening...")
    63  	go func() {
    64  		fatal(http.Serve(listener, nil))
    65  	}()
    66  }
    67  
    68  var start func()
    69  
    70  func fatal(err error) {
    71  	if err != nil {
    72  		log.Fatal(err)
    73  	}
    74  }
    75  
    76  // Define some custom types were going to use within our tokens
    77  type CustomerInfo struct {
    78  	Name string
    79  	Kind string
    80  }
    81  
    82  type CustomClaimsExample struct {
    83  	*jwt.StandardClaims
    84  	TokenType string
    85  	CustomerInfo
    86  }
    87  
    88  func Example_getTokenViaHTTP() {
    89  	// See func authHandler for an example auth handler that produces a token
    90  	res, err := http.PostForm(fmt.Sprintf("http://localhost:%v/authenticate", serverPort), url.Values{
    91  		"user": {"test"},
    92  		"pass": {"known"},
    93  	})
    94  	if err != nil {
    95  		fatal(err)
    96  	}
    97  
    98  	if res.StatusCode != 200 {
    99  		fmt.Println("Unexpected status code", res.StatusCode)
   100  	}
   101  
   102  	// Read the token out of the response body
   103  	buf := new(bytes.Buffer)
   104  	io.Copy(buf, res.Body)
   105  	res.Body.Close()
   106  	tokenString := strings.TrimSpace(buf.String())
   107  
   108  	// Parse the token
   109  	token, err := jwt.ParseWithClaims(tokenString, &CustomClaimsExample{}, func(token *jwt.Token) (interface{}, error) {
   110  		// since we only use the one private key to sign the tokens,
   111  		// we also only use its public counter part to verify
   112  		return verifyKey, nil
   113  	})
   114  	fatal(err)
   115  
   116  	claims := token.Claims.(*CustomClaimsExample)
   117  	fmt.Println(claims.CustomerInfo.Name)
   118  
   119  	//Output: test
   120  }
   121  
   122  func Example_useTokenViaHTTP() {
   123  
   124  	// Make a sample token
   125  	// In a real world situation, this token will have been acquired from
   126  	// some other API call (see Example_getTokenViaHTTP)
   127  	token, err := createToken("foo")
   128  	fatal(err)
   129  
   130  	// Make request.  See func restrictedHandler for example request processor
   131  	req, err := http.NewRequest("GET", fmt.Sprintf("http://localhost:%v/restricted", serverPort), nil)
   132  	fatal(err)
   133  	req.Header.Set("Authorization", fmt.Sprintf("Bearer %v", token))
   134  	res, err := http.DefaultClient.Do(req)
   135  	fatal(err)
   136  
   137  	// Read the response body
   138  	buf := new(bytes.Buffer)
   139  	io.Copy(buf, res.Body)
   140  	res.Body.Close()
   141  	fmt.Println(buf.String())
   142  
   143  	// Output: Welcome, foo
   144  }
   145  
   146  func createToken(user string) (string, error) {
   147  	// create a signer for rsa 256
   148  	t := jwt.New(jwt.GetSigningMethod("RS256"))
   149  
   150  	// set our claims
   151  	t.Claims = &CustomClaimsExample{
   152  		&jwt.StandardClaims{
   153  			// set the expire time
   154  			// see http://tools.ietf.org/html/draft-ietf-oauth-json-web-token-20#section-4.1.4
   155  			ExpiresAt: time.Now().Add(time.Minute * 1).Unix(),
   156  		},
   157  		"level1",
   158  		CustomerInfo{user, "human"},
   159  	}
   160  
   161  	// Creat token string
   162  	return t.SignedString(signKey)
   163  }
   164  
   165  // reads the form values, checks them and creates the token
   166  func authHandler(w http.ResponseWriter, r *http.Request) {
   167  	// make sure its post
   168  	if r.Method != "POST" {
   169  		w.WriteHeader(http.StatusBadRequest)
   170  		fmt.Fprintln(w, "No POST", r.Method)
   171  		return
   172  	}
   173  
   174  	user := r.FormValue("user")
   175  	pass := r.FormValue("pass")
   176  
   177  	log.Printf("Authenticate: user[%s] pass[%s]\n", user, pass)
   178  
   179  	// check values
   180  	if user != "test" || pass != "known" {
   181  		w.WriteHeader(http.StatusForbidden)
   182  		fmt.Fprintln(w, "Wrong info")
   183  		return
   184  	}
   185  
   186  	tokenString, err := createToken(user)
   187  	if err != nil {
   188  		w.WriteHeader(http.StatusInternalServerError)
   189  		fmt.Fprintln(w, "Sorry, error while Signing Token!")
   190  		log.Printf("Token Signing error: %v\n", err)
   191  		return
   192  	}
   193  
   194  	w.Header().Set("Content-Type", "application/jwt")
   195  	w.WriteHeader(http.StatusOK)
   196  	fmt.Fprintln(w, tokenString)
   197  }
   198  
   199  // only accessible with a valid token
   200  func restrictedHandler(w http.ResponseWriter, r *http.Request) {
   201  	// Get token from request
   202  	token, err := request.ParseFromRequestWithClaims(r, request.OAuth2Extractor, &CustomClaimsExample{}, func(token *jwt.Token) (interface{}, error) {
   203  		// since we only use the one private key to sign the tokens,
   204  		// we also only use its public counter part to verify
   205  		return verifyKey, nil
   206  	})
   207  
   208  	// If the token is missing or invalid, return error
   209  	if err != nil {
   210  		w.WriteHeader(http.StatusUnauthorized)
   211  		fmt.Fprintln(w, "Invalid token:", err)
   212  		return
   213  	}
   214  
   215  	// Token is valid
   216  	fmt.Fprintln(w, "Welcome,", token.Claims.(*CustomClaimsExample).Name)
   217  	return
   218  }
   219  

View as plain text