...

Source file src/github.com/ory/fosite/integration/clients/jwt_bearer.go

Documentation: github.com/ory/fosite/integration/clients

     1  /*
     2   * Copyright © 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   *
    16   * @author		Aeneas Rekkas <aeneas+oss@aeneas.io>
    17   * @copyright 	2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
    18   * @license 	Apache-2.0
    19   *
    20   */
    21  
    22  package clients
    23  
    24  import (
    25  	"context"
    26  	"crypto/rsa"
    27  	"encoding/json"
    28  	"io"
    29  	"io/ioutil"
    30  	"net/http"
    31  	"net/url"
    32  	"strings"
    33  
    34  	"gopkg.in/square/go-jose.v2"
    35  	"gopkg.in/square/go-jose.v2/jwt"
    36  )
    37  
    38  const jwtBearerGrantType = "urn:ietf:params:oauth:grant-type:jwt-bearer"
    39  
    40  type JWTBearer struct {
    41  	tokenURL string
    42  	header   *Header
    43  	client   *http.Client
    44  
    45  	Signer jose.Signer
    46  }
    47  
    48  type Token struct {
    49  	AccessToken  string `json:"access_token"`
    50  	TokenType    string `json:"token_type,omitempty"`
    51  	RefreshToken string `json:"refresh_token,omitempty"`
    52  	ExpiresIn    int64  `json:"expires_in,omitempty"`
    53  }
    54  
    55  type Header struct {
    56  	Algorithm string `json:"alg"`
    57  	Typ       string `json:"typ"`
    58  	KeyID     string `json:"kid,omitempty"`
    59  }
    60  
    61  type JWTBearerPayload struct {
    62  	*jwt.Claims
    63  
    64  	PrivateClaims map[string]interface{}
    65  }
    66  
    67  func (c *JWTBearer) SetPrivateKey(keyID string, privateKey *rsa.PrivateKey) error {
    68  	jwk := jose.JSONWebKey{Key: privateKey, KeyID: keyID, Algorithm: string(jose.RS256)}
    69  	signingKey := jose.SigningKey{
    70  		Algorithm: jose.RS256,
    71  		Key:       jwk,
    72  	}
    73  	signerOptions := &jose.SignerOptions{}
    74  	signerOptions.WithType("JWT")
    75  
    76  	sig, err := jose.NewSigner(signingKey, signerOptions)
    77  	if err != nil {
    78  		return err
    79  	}
    80  
    81  	c.Signer = sig
    82  
    83  	return nil
    84  }
    85  
    86  func (c *JWTBearer) GetToken(ctx context.Context, payloadData *JWTBearerPayload, scope []string) (*Token, error) {
    87  	builder := jwt.Signed(c.Signer).
    88  		Claims(payloadData.Claims).
    89  		Claims(payloadData.PrivateClaims)
    90  
    91  	assertion, err := builder.CompactSerialize()
    92  	if err != nil {
    93  		return nil, err
    94  	}
    95  
    96  	requestBodyReader, err := c.getRequestBodyReader(assertion, scope)
    97  	if err != nil {
    98  		return nil, err
    99  	}
   100  
   101  	request, err := http.NewRequestWithContext(ctx, "POST", c.tokenURL, requestBodyReader)
   102  	if err != nil {
   103  		return nil, err
   104  	}
   105  
   106  	request.Header.Set("Content-Type", "application/x-www-form-urlencoded")
   107  
   108  	response, err := c.client.Do(request)
   109  	if err != nil {
   110  		return nil, err
   111  	}
   112  
   113  	defer response.Body.Close()
   114  
   115  	body, err := ioutil.ReadAll(response.Body)
   116  	if err != nil {
   117  		return nil, err
   118  	}
   119  
   120  	if c := response.StatusCode; c < 200 || c > 299 {
   121  		return nil, &RequestError{
   122  			Response: response,
   123  			Body:     body,
   124  		}
   125  	}
   126  
   127  	token := &Token{}
   128  
   129  	if err := json.Unmarshal(body, token); err != nil {
   130  		return nil, err
   131  	}
   132  
   133  	return token, err
   134  }
   135  
   136  func (c *JWTBearer) getRequestBodyReader(assertion string, scope []string) (io.Reader, error) {
   137  	data := url.Values{}
   138  	data.Set("grant_type", jwtBearerGrantType)
   139  	data.Set("assertion", string(assertion))
   140  
   141  	if len(scope) != 0 {
   142  		data.Set("scope", strings.Join(scope, " "))
   143  	}
   144  
   145  	return strings.NewReader(data.Encode()), nil
   146  }
   147  
   148  func NewJWTBearer(tokenURL string) *JWTBearer {
   149  	return &JWTBearer{
   150  		client:   &http.Client{},
   151  		tokenURL: tokenURL,
   152  	}
   153  }
   154  

View as plain text