@@ -672,7 +672,7 @@ Service_.prototype.refresh = function() {
672
672
* Custom values associated with the service can be stored here as well.
673
673
* The key <code>null</code> is used to to store the token and should not
674
674
* be used.
675
- * @return {Storage } The service's storage.
675
+ * @return {Storage_ } The service's storage.
676
676
*/
677
677
Service_ . prototype . getStorage = function ( ) {
678
678
if ( ! this . storage_ ) {
@@ -703,20 +703,35 @@ Service_.prototype.getToken = function(optSkipMemoryCheck) {
703
703
} ;
704
704
705
705
/**
706
- * Determines if a retrieved token is still valid.
706
+ * Determines if a retrieved token is still valid. This will return false if
707
+ * either the authorization token or the ID token has expired.
707
708
* @param {Object } token The token to validate.
708
709
* @return {boolean } True if it has expired, false otherwise.
709
710
* @private
710
711
*/
711
712
Service_ . prototype . isExpired_ = function ( token ) {
713
+ var expired = false ;
714
+ var now = getTimeInSeconds_ ( new Date ( ) ) ;
715
+
716
+ // Check the authorization token's expiration.
712
717
var expiresIn = token . expires_in_sec || token . expires_in || token . expires ;
713
- if ( ! expiresIn ) {
714
- return false ;
715
- } else {
718
+ if ( expiresIn ) {
716
719
var expiresTime = token . granted_time + Number ( expiresIn ) ;
717
- var now = getTimeInSeconds_ ( new Date ( ) ) ;
718
- return expiresTime - now < Service_ . EXPIRATION_BUFFER_SECONDS_ ;
720
+ if ( expiresTime - now < Service_ . EXPIRATION_BUFFER_SECONDS_ ) {
721
+ expired = true ;
722
+ }
719
723
}
724
+
725
+ // Check the ID token's expiration, if it exists.
726
+ if ( token . id_token ) {
727
+ var payload = decodeJwt_ ( token . id_token ) ;
728
+ if ( payload . exp &&
729
+ payload . exp - now < Service_ . EXPIRATION_BUFFER_SECONDS_ ) {
730
+ expired = true ;
731
+ }
732
+ }
733
+
734
+ return expired ;
720
735
} ;
721
736
722
737
/**
@@ -767,10 +782,6 @@ Service_.prototype.createJwt_ = function() {
767
782
'Token URL' : this . tokenUrl_ ,
768
783
'Issuer or Client ID' : this . issuer_ || this . clientId_
769
784
} ) ;
770
- var header = {
771
- alg : 'RS256' ,
772
- typ : 'JWT'
773
- } ;
774
785
var now = new Date ( ) ;
775
786
var expires = new Date ( now . getTime ( ) ) ;
776
787
expires . setMinutes ( expires . getMinutes ( ) + this . expirationMinutes_ ) ;
@@ -792,12 +803,7 @@ Service_.prototype.createJwt_ = function() {
792
803
claimSet [ key ] = additionalClaims [ key ] ;
793
804
} ) ;
794
805
}
795
- var toSign = Utilities . base64EncodeWebSafe ( JSON . stringify ( header ) ) + '.' +
796
- Utilities . base64EncodeWebSafe ( JSON . stringify ( claimSet ) ) ;
797
- var signatureBytes =
798
- Utilities . computeRsaSha256Signature ( toSign , this . privateKey_ ) ;
799
- var signature = Utilities . base64EncodeWebSafe ( signatureBytes ) ;
800
- return toSign + '.' + signature ;
806
+ return encodeJwt_ ( claimSet , this . privateKey_ ) ;
801
807
} ;
802
808
803
809
/**
@@ -1001,7 +1007,7 @@ Storage_.prototype.reset = function() {
1001
1007
1002
1008
/**
1003
1009
* Removes a stored value.
1004
- * @param {string } key The key.
1010
+ * @param {string } prefixedKey The key.
1005
1011
*/
1006
1012
Storage_ . prototype . removeValueWithPrefixedKey_ = function ( prefixedKey ) {
1007
1013
if ( this . properties_ ) {
@@ -1111,7 +1117,7 @@ function extend_(destination, source) {
1111
1117
* Gets a copy of an object with all the keys converted to lower-case strings.
1112
1118
*
1113
1119
* @param {Object } obj The object to copy.
1114
- * @return {Object } a shallow copy of the object with all lower-case keys.
1120
+ * @return {Object } A shallow copy of the object with all lower-case keys.
1115
1121
*/
1116
1122
function toLowerCaseKeys_ ( obj ) {
1117
1123
if ( obj === null || typeof obj !== 'object' ) {
@@ -1125,6 +1131,40 @@ function toLowerCaseKeys_(obj) {
1125
1131
} , { } ) ;
1126
1132
}
1127
1133
1134
+ /* exported encodeJwt_ */
1135
+ /**
1136
+ * Encodes and signs a JWT.
1137
+ *
1138
+ * @param {Object } payload The JWT payload.
1139
+ * @param {string } key The key to use when generating the signature.
1140
+ * @return {string } The encoded and signed JWT.
1141
+ */
1142
+ function encodeJwt_ ( payload , key ) {
1143
+ var header = {
1144
+ alg : 'RS256' ,
1145
+ typ : 'JWT'
1146
+ } ;
1147
+ var toSign = Utilities . base64EncodeWebSafe ( JSON . stringify ( header ) ) + '.' +
1148
+ Utilities . base64EncodeWebSafe ( JSON . stringify ( payload ) ) ;
1149
+ var signatureBytes =
1150
+ Utilities . computeRsaSha256Signature ( toSign , key ) ;
1151
+ var signature = Utilities . base64EncodeWebSafe ( signatureBytes ) ;
1152
+ return toSign + '.' + signature ;
1153
+ }
1154
+
1155
+ /* exported decodeJwt_ */
1156
+ /**
1157
+ * Decodes and returns the parts of the JWT. The signature is not verified.
1158
+ *
1159
+ * @param {string } jwt The JWT to decode.
1160
+ * @return {Object } The decoded payload.
1161
+ */
1162
+ function decodeJwt_ ( jwt ) {
1163
+ var payload = jwt . split ( '.' ) [ 1 ] ;
1164
+ var blob = Utilities . newBlob ( Utilities . base64DecodeWebSafe ( payload ) ) ;
1165
+ return JSON . parse ( blob . getDataAsString ( ) ) ;
1166
+ }
1167
+
1128
1168
/****** code end *********/
1129
1169
; (
1130
1170
function copy ( src , target , obj ) {
0 commit comments