jwt: allow setting a custom expiry time for JWT tokens
The current implementation of JWS/JWT in this package uses a fixed
1 hour expiry time for JWT tokens.
Some services do not accept such a long expiry time, e.g. Salesforce,
which defaults to a 5 minute expiry.
https://help.salesforce.com/HTViewHelpDoc?id=remoteaccess_oauth_jwt_flow.htm
This change adds an Expires time.Duration property to the jwt.Config
struct that, if set, will be used to calculate the jws.ClaimSet Exp property.
It allows a custom expiry to be set on a JWT token.
This change is backward compatible and will revert to previous behaviour if
the Expires property is not set.
Fixes golang/oauth2#151
Change-Id: I3159ac2a5711ef10389d83c0e290bfc7a9f54015
Reviewed-on: https://go-review.googlesource.com/14681
Reviewed-by: Burcu Dogan <jbd@google.com>
diff --git a/jws/jws.go b/jws/jws.go
index 37d8651..6e03198 100644
--- a/jws/jws.go
+++ b/jws/jws.go
@@ -41,23 +41,22 @@
// See http://tools.ietf.org/html/draft-jones-json-web-token-10#section-4.3
// This array is marshalled using custom code (see (c *ClaimSet) encode()).
PrivateClaims map[string]interface{} `json:"-"`
-
- exp time.Time
- iat time.Time
}
func (c *ClaimSet) encode() (string, error) {
- if c.exp.IsZero() || c.iat.IsZero() {
- // Reverting time back for machines whose time is not perfectly in sync.
- // If client machine's time is in the future according
- // to Google servers, an access token will not be issued.
- now := time.Now().Add(-10 * time.Second)
- c.iat = now
- c.exp = now.Add(time.Hour)
+ // Reverting time back for machines whose time is not perfectly in sync.
+ // If client machine's time is in the future according
+ // to Google servers, an access token will not be issued.
+ now := time.Now().Add(-10 * time.Second)
+ if c.Iat == 0 {
+ c.Iat = now.Unix()
}
-
- c.Exp = c.exp.Unix()
- c.Iat = c.iat.Unix()
+ if c.Exp == 0 {
+ c.Exp = now.Add(time.Hour).Unix()
+ }
+ if c.Exp < c.Iat {
+ return "", fmt.Errorf("jws: invalid Exp must be later than Iat", c.Exp)
+ }
b, err := json.Marshal(c)
if err != nil {
diff --git a/jwt/jwt.go b/jwt/jwt.go
index 205d23e..11a2687 100644
--- a/jwt/jwt.go
+++ b/jwt/jwt.go
@@ -54,6 +54,9 @@
// TokenURL is the endpoint required to complete the 2-legged JWT flow.
TokenURL string
+
+ // Expires optionally specifies how long the token is valid for.
+ Expires time.Duration
}
// TokenSource returns a JWT TokenSource using the configuration
@@ -95,6 +98,9 @@
// to be compatible with legacy OAuth 2.0 providers.
claimSet.Prn = subject
}
+ if t := js.conf.Expires; t > 0 {
+ claimSet.Exp = time.Now().Add(t).Unix()
+ }
payload, err := jws.Encode(defaultHeader, claimSet, pk)
if err != nil {
return nil, err