JwtSecurityToken expiration date is two hours apart - api

In my .net core api application, I use:
var dt = DateTime.Now.AddMinutes(60); // time is 2018-04-27 14:49:00
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_config["Tokens:Key"]));
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
var claims = new[]
{
new Claim(JwtRegisteredClaimNames.Sub, user.Email),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
new Claim(JwtRegisteredClaimNames.UniqueName, user.UserName)
};
var token = new JwtSecurityToken(
_config["Tokens:Issuer"],
_config["Tokens:Audience"],
claims,
expires: dt,
signingCredentials: creds);
token.ValidTo is shown as 2018-04-27 12:49:00 ...
Why ?

It's because of the different timezones. Your timezone is probably UTC+2, and your variable dt contains the time in local time.
But JwtSecurityToken.ValidTo is a DateTime value which contains a time in UTC. The resulting JWT will give you a value (exp claim) based in Unix Epoch Time in seconds sine 1970-01-01 00:00 UTC.
In your case exp will be
1524833340
which equals
2018-04-27 12:49:00 UTC (14:49 in UTC+2)
as you can check here and the JWT framework knows how to handle that, independent from the timezone.
The behaviour is correct and you don't need to change anything.

In server side create token method, use Utc time to generate expiration time:
var token = new JwtSecurityToken(
issuer: _configuration["JWT:ValidIssuer"],
audience: _configuration["JWT:ValidAudience"],
expires: DateTime.UtcNow.AddMinutes(tokenValidityInMinutes),
claims: authClaims,
signingCredentials: new SigningCredentials(authSigningKey, SecurityAlgorithms.HmacSha256)
);
and in client side check for Utc time :
var identity = string.IsNullOrEmpty(tokenDTO?.Token) || tokenDTO?.Expiration < DateTime.UtcNow
In fact local time makes this problem, so you need to create an expiration time based on Utc and check it with DateTime.UtcNow

Related

WebRTC/ Coturn Authentication using TURN REST API flag (use-auth-secret), based upon authentication secret

I was playing with this was able to get it working immediately using Node/Javascript, took a while using Golang (this is just generating the user/password to be sent to coturn.) Notice the secret should match the coturn configuration and in the API JS/Go side.
The configuration on coturn: /etc/turnserver.conf
listening-port=443
tls-listening-port=443
listening-ip=10.100.0.2
relay-ip=10.100.0.2
external-ip=123.456.78.9
min-port=10000
max-port=20000
verbose
fingerprint
lt-cred-mech
server-name=myserver
realm=myserver
cert=/etc/SSL/fullchain.pem
pkey=/etc/SSL/privkey.pem
log-file=/var/log/turnserver.log
use-auth-secret
static-auth-secret=MySecret
The following is Node/Js Implementation API (copied from elsewhere - worked):
var crypto = require('crypto');
var unixTimeStamp = parseInt(Date.now()/1000) + 24*3600, // this credential valid for 24 hours
TempUser = [unixTimeStamp, "SomeUser"].join(':'),
TempPassword,
hmac = crypto.createHmac('sha1', "MySecret");
hmac.setEncoding('base64');
hmac.write(TempUser);
hmac.end();
TempPassword = hmac.read();
The following is GOLANG Implementation API (took a while):
UserId := "SomeUser"
// This worked, returned the exact seconds
timestamp := strconv.FormatInt(time.Now().UTC().Unix()+24*3600, 10)
// Example: The above is 1602692130
secret := "MySecret"
TempUser := timestamp + ":" + UserId // For API Auth, coturn expects this format, the timestamp is the expiry date of the final temp user/password.
// Create a new HMAC by defining the hash type and the key (as byte array)
//h := hmac.New(sha256.New, []byte(secret)) // sha256 does not work, use sha1
h := hmac.New(sha1.New, []byte(secret))
h.Write([]byte(TempUser))
//sha := b64.URLEncoding.EncodeToString(h.Sum(nil)) // URLEncoding did not work
TempPassword := b64.StdEncoding.EncodeToString(h.Sum(nil)) // StdEncoding worked
The JS on the Webrtc client. Notice we are using the TempUser and TempPassword here to be sent to coturn.
...
const stunUrl = 'stun:mystun_server',
turnUsername = TempUser,
turnPassword = TempPassword,
...
'iceServers': [
{ 'url': stunUrl },
{
'urls': turnUrl1,
'username': turnUsername,
'credential': turnPassword
},
Now coturn will authenticate using the TempUser and TempPassword above. Hope someone will find this useful. Thanks!

How to extract JWT Expiry date without resource server?

I have a Single Page Application which requests JWTs from AWS cognito to access protected resources in a resource server. However, when the JWT expires, I would like to programmatically refresh it. To do this, I need to know if the token is expired to trigger a refresh. Here is the JWT below.
{
"sub": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
"aud": "xxxxxxxxxxxxexample",
"email_verified": true,
"token_use": "id",
"auth_time": 1500009400,
"iss": "https://cognito-idp.us-east-1.amazonaws.com/us-east-1_example",
"cognito:username": "janedoe",
"exp": 1500013000, // <---- this is what we want
"given_name": "Jane",
"iat": 1500009400,
"email": "janedoe#example.com"
}
My dilemma however is that I do not know how to check when it expires without sending it to the resource server to validate it and I cannot do validation on front end as that would expose application secrets. I figure the exp variable is possibly the number of milliseconds from a particular date, however I'm not sure (and nothing on Google corroborates this).
So I'd like to ask, how does one determine the expiry date from the exp variable?
The exp claim is indeed what you're looking for. It's the expiration time, encoded as a numeric value representing the number of seconds since 1970-01-01 00:00 UTC (also refered to as UNIX Epoch time)
You can check your token on https://jwt.io/ and see the converted timestamp, if you point with the mouse on the numeric timestamp.
Here's a small js snippet, that demonstrates how you can calculate the remaining time:
// exp = 2019-09-01 00:00 UTC
var exp = 1567296000
var currentTimeSeconds = Math.round(+new Date()/1000);
console.log(currentTimeSeconds)
var remainingSeconds = exp - currentTimeSeconds
console.log(remainingSeconds + " seconds remaining")
and here is how to convert it to date type, output in local time:
// exp = 2019-09-01 00:00 UTC
var exp = 1567296000
var expDate = new Date(exp*1000);
var expYear = expDate.getYear() + 1900
var expMonth = expDate.getMonth() + 1
var expDay = expDate.getDate()
var expHours = "0" + expDate.getHours()
var expMinutes = "0" + expDate.getMinutes()
var expSeconds = "0" + expDate.getSeconds()
var expFormatted = expYear + "-" + expMonth + "-" + expDay + " " + expHours.substr(-2) + ':' + expMinutes.substr(-2) + ':' + expSeconds.substr(-2);
console.log(expFormatted)
Cognito provides some standard session validation in their libraries.
If you're using JavaScript, you can get a valid set of tokens using
CognitoUser.getSession((err, session) => {
...
})
This checks the id and access tokens and if either is expired, will retrieve updated tokens using the refresh token.

Azure container shared access signature expiring

I'm having trouble with Azure Blobs and Shared Access Signatures when they expire. I need to grant access to a blob for longer than 1 hour (1 year), so I'm using a named container policy, but unfortunately . Its expiring after 1 hr
SharedAccessPolicy sharedAccessPolicy = new SharedAccessPolicy();
sharedAccessPolicy.Permissions = SharedAccessPermissions.Read;
sharedAccessPolicy.SharedAccessStartTime = DateTime.UtcNow;
//sharedAccessPolicy.SharedAccessExpiryTime = DateTime.UtcNow.AddYear(1); No need to define expiry time here.
BlobContainerPermissions blobContainerPermissions = new BlobContainerPermissions();
blobContainerPermissions.SharedAccessPolicies.Add("default", sharedAccessPolicy);
container.SetPermissions(blobContainerPermissions);
Console.WriteLine("Press any key to continue....");
Console.ReadLine();
CloudBlob blob = container.GetBlobReference(path);
string sas = blob.GetSharedAccessSignature(new SharedAccessPolicy()
{
SharedAccessExpiryTime = DateTime.UtcNow.AddDays(7),//add expiry date only when you're creating the signed URL
}
, "default");
Console.WriteLine(blob.Uri.AbsoluteUri + sas);
Process.Start(new ProcessStartInfo(blob.Uri.AbsoluteUri + sas));
Console.WriteLine("Press any key to continue....");
Console.ReadLine();

Issue with BTC-e API in App Script, method parameter

I am trying to incorporate the BTC-e.com API in to a google docs spreadsheet.
The API documentation is here: https://btc-e.com/api/documentation
The method name is sent via POST parameter method.
As the URLFetchApp requires me to set the type of request as POST by a parameter method and I then have another parameter called method to be set as getInfo.
How can I go about setting the fetch method as POST and have the API parameter method as getInfo.
Below is the function this relates too. Also I am sure there a more issues in my work I am yet to find.
function inventory() {
var nonce=Number(SpreadsheetApp.getActiveSheet().getRange('K2').getValue());
var token=SpreadsheetApp.getActiveSheet().getRange('K1').getValue();
var tokenEndpoint = "https://btc-e.com/tapi";
var sign= 'TEMP'
var head = {
'Content-Type': 'application/x-www-form-urlencoded',
'Key': token,
'Sign': sign
}
var params = {
method : "POST",
method : "getInfo",
headers: head,
contentType: 'application/x-www-form-urlencoded',
method : "getInfo",
nonce: nonce
}
var request = UrlFetchApp.getRequest(tokenEndpoint, params);
var response = UrlFetchApp.fetch(tokenEndpoint, params);
var response2=String(response);
SpreadsheetApp.getActiveSheet().getRange('K2').setValue(nonce+1);
SpreadsheetApp.getActiveSheet().getRange('I16').setValue(response2);
SpreadsheetApp.getActiveSheet().getRange('I17').setValue(nonce);
}
This just yields the error
Attribute provided with invalid value: method
Thanks,
Steve
PS: First time posting, I tried to get the format correct.
I made the following Google JavaScript function to do POST access to BTC-e. You can find this function in action in the example spreadsheet I made to demonstrate the BTC-e API functions.
function btceHttpPost(keyPair, method, params, nonce) {
if (keyPair === undefined) {
return "{'error':'missing key pair'}"
}
if (params === undefined) {
params = '';
}
// Cleanup keypair, remove all \s (any whitespace)
var keyPair = keyPair.replace(/[\s]/g, '');
// Keypair example: "AFE730YV-S9A4FXBJ-NQ12HXS9-CA3S3MPM-CKQLU0PG,96a00f086824ddfddd9085a5c32b8a7b225657ae2fe9c4483b4c109fab6bf1a7"
keyPair = keyPair.split(',');
var pubKey = keyPair[0];
var privKey = keyPair[1];
// As specified on the BTC-e api (https://btc-e.com/api/documentation) the
// nonce POST parameter must be an incrementing integer (>0). The easiest
// implementation is the use of a timestamp (TS), so there is no need
// for persistant storage. Preferable, the resolution of the TS should be
// small enough the handle the desired call-frequency (a sleep of the TS
// resolution can fix this but I don't like such a waste). Another
// consideration is the sizeof the nonce supported by BTC-e. Experiments
// revealed this is a 32 bit unsigned number. The native JavaScript TS,
// stored in a float, can be 53 bits and has a resolution of 1 ms.
if (nonce === undefined)
// This time stamp counts amount of 200ms ticks starting from Jan 1st, 2014 UTC
// On 22 Mar 2041 01:17:39 UTC, it will overflow the 32 bits and will fail
// the nonce key for BTC-e
var nonce = Math.floor((Date.now() - Date.UTC(2014,0)) / 200);
// Construct payload message
var msg = 'nonce=' + nonce + '&method=' + method + params;
var msgSign = Utilities.computeHmacSignature(Utilities.MacAlgorithm.HMAC_SHA_512, msg, privKey);
// Convert encoded message from byte[] to hex string
for (var msgSignHex = [], i = 0; i < msgSign.length; i++) {
// Doing it nibble by nibble makes sure we keep leading zero's
msgSignHex.push(((msgSign[i] >>> 4) & 0xF).toString(16));
msgSignHex.push((msgSign[i] & 0xF).toString(16));
}
msgSignHex = msgSignHex.join('');
var httpHeaders = {'Key': pubKey, 'Sign': msgSignHex};
var fetchOptions = {'method': 'post', 'headers': httpHeaders, 'payload': msg};
var reponse = UrlFetchApp.fetch('https://btc-e.com/tapi', fetchOptions);
return reponse.getContentText();
};
The problem looks to be with your params object . You have method set thrice in the same object, which is a source of confusion.
Next, take a look at the documentation for UrlFetchApp.fetch() ( https://developers.google.com/apps-script/reference/url-fetch/url-fetch-app#fetch(String,Object) ) . The method can take a value of post, get, delete, put.
The getInfo should probably be appended to your URL to make it
var tokenEndpoint = "https://btc-e.com/tapi/getInfo"
Per the docs, you also have to put in more parameters to the request, nonce, api key etc. Use this as a starting point, revisit the documentation and get back to SO if you still have trouble

Exchange Api send incorrect invitation in Israel timezone

I faced to following problem with sending invitation in .net using exchange API
Send invitation in Israel timezone with start time =09/09/2013 4.30 Israel.
But it is displayed in outlook 09/09/2013 6.30 Israel.
It works properly for other time zones for example for EST.
Does anybody has any idea how to fix this?
Sample:
service.AutodiscoverUrl(loginForm.tbEmailAddress.Text, f);
TimeZoneInfo timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Israel Standard Time");
Appointment appointment = new Appointment(service);
appointment.Subject = "subj";
appointment.Body = new MessageBody(BodyType.Text, "body");
appointment.StartTimeZone = timeZoneInfo;
appointment.Start = GetDateTime(new DateTime(2013, 09, 09, 04, 0, 0));
appointment.EndTimeZone = timeZoneInfo;
appointment.End = GetDateTime(new DateTime(2013, 09, 09, 04, 30, 0));
appointment.IsAllDayEvent = false;
appointment.Importance = Importance.Normal;
appointment.RequiredAttendees.Add("Lena", "email...");
appointment.Save(SendInvitationsMode.SendOnlyToAll);
...
private static DateTime GetDateTime(DateTime dateTime)
{
return new DateTime(dateTime.Year, dateTime.Month, dateTime.Day, dateTime.Hour, dateTime.Minute,
dateTime.Second, dateTime.Millisecond, DateTimeKind.Unspecified
);
}
I use Microsoft.Exchange.WebServices.dll 15.0.516.14
it's actually a known issue with Exchange EWS itself. Developer can only trust the date time returned without the timezone information, and the correct timezone for that time should be UTC always.