/// <summary>Inserts the specified refresh token. Called when creating a refresh token.</summary> /// <param name="refreshToken">The refresh token.</param> /// <returns>The inserted refresh token. <c>null</c> if the insertion was unsuccessful.</returns> public async Task <IRefreshToken> InsertRefreshToken(IRefreshToken refreshToken) { var token = new RedisRefreshToken(refreshToken); if (!token.IsValid()) { throw new ArgumentException($"The refresh token is invalid: {JsonConvert.SerializeObject(token)}", nameof(refreshToken)); } var key = this.GenerateKeyPath(token); var db = this.GetDatabase(); var tran = db.CreateTransaction(); try { this.Configuration.Log.DebugFormat("Inserting refresh token hash in key {0}", key); // Add hash to key tran.HashSetAsync(key, token.ToHashEntries()); var expires = token.ValidTo.ToUnixTime(); this.Configuration.Log.DebugFormat("Inserting key {0} to refresh token set with score {1}", key, expires); // Add key to index for future reference. The score is the expire time in seconds since epoch. tran.SortedSetAddAsync($"{this.Configuration.RefreshTokenPrefix}:_index:expires", key, expires); // Add key to hashed set for future reference by client id, redirect uri or subject. The value is the expire time in seconds since epoch. tran.HashSetAsync($"{this.Configuration.RefreshTokenPrefix}:_index:client:{token.ClientId}", key, expires); tran.HashSetAsync($"{this.Configuration.RefreshTokenPrefix}:_index:redirecturi:{token.RedirectUri}", key, expires); tran.HashSetAsync($"{this.Configuration.RefreshTokenPrefix}:_index:subject:{token.Subject}", key, expires); this.Configuration.Log.DebugFormat("Making key {0} expire at {1}", key, token.ValidTo); // Make the key expire when the code times out tran.KeyExpireAsync(key, token.ValidTo.UtcDateTime); await tran.ExecuteAsync(); return(token); } catch (Exception ex) { this.Configuration.Log.Error("Error when inserting refresh token", ex); } return(null); }