How to set the UserTokenProvider token expiration - c#

We're working on a new ASP.NET MVC 4.1 app. We're hooking up the ASP.NET Identity stuff, and we're struggling with tokens for password reset and new invite. I can't seem to find a way to set the expiration time for the tokens that are generated, and it seems to be set at around 10 mins by default. We're using a EmailTokenProvider as the user token provider, because it seems to work well with the security stamp on the user.
How can we set the expiration for the tokens - ideally we'd like to set it differently for the invite Vs the reset password tokens.
Our user manager looks like this:
var manager = new UserManager<User, long>(new UserStore(new UserRepository()));
manager.UserValidator = new UserValidator<User, long>(manager) {AllowOnlyAlphanumericUserNames = false, RequireUniqueEmail = true};
manager.UserTokenProvider = new EmailTokenProvider<User, long>();
When a user requests a reset password link we call
var token = await _userManager.GeneratePasswordResetTokenAsync(user.Id); to get the token, and pass that on to the user.
When a user is invited, we call:
var token = await _userManager.GenerateUserTokenAsync("FirstLogin", user.Id);
to get the token, and send.

The default implementations of the token providers in 2.0 don't allow you to change the token expiration, this is something we are considering for identity 3.0.

If I understand your question well, following could help:
private static string CalculateToken(User user)
{
byte[] time = BitConverter.GetBytes(DateTime.UtcNow.ToBinary());
byte[] key = BitConverter.GetBytes(user.ID);
string token = Convert.ToBase64String(time.Concat(key).ToArray());
return token;
}
And then:
DateTime time = DateTime.FromBinary(BitConverter.ToInt64(data, 0));
int id = BitConverter.ToInt32(data, 8);
if (time< DateTime.UtcNow.AddMinutes(-10) || user.ID != id)
{
//too old or IDs not matching
}

Related

How to update cognito access token .net

I'm struggling with a problem of how to update the users Access/Id token on expiry I know how to get new tokens, i'm trying to work out how to update the users current/expired token once I have the updated ones? following code works fine and the response returns new access/id tokens, a null session (which is odd). I have tried GetUserReequest using the currrent access token then updating it, to no effect. Documentation is a bit sparse on methods that expose access token also
public async Task RefreshTokens(string token)
{
var request = new AdminInitiateAuthRequest
{
UserPoolId = userpool,
ClientId = clientId,
AuthFlow = AuthFlowType.REFRESH_TOKEN_AUTH,
AuthParameters =
{
{"REFRESH_TOKEN", token},
{"SECRET_HASH", secret}
}
};
var response = await _cognitoIdentityProvider.AdminInitiateAuthAsync(request);
//Do something here to update users tokens
}

Firebase Authenticate Simple Login

TL;DR : Is there any way to use the auth=CREDENTIALS with the Simple Login (Email/Password) in Firebase?
I am trying to connect my C# Application's users to my Firebase. I could set up pretty much all calls using my Secret Token, but now I need to be able to, at least, get the current user UID so I know where the data should be sent to.
The way I went with my PUSH, PUT, GET request was something like this, using my secret token as login:
var authToken = "SECRET";
url = "https://MyLocation.firebaseio.com/" + url + ".json?auth=" + authToken;
return WebRequest.Create(url);
But now I'd like to get something supporting the Email/Password simple login, something like this:
var authToken = "{email:an#email.com, password:thePassword}";
url = "https://MyLocation.firebaseio.com/" + url + ".json?auth=" + authToken;
return WebRequest.Create(url);
My tries using CURL weren't successful... Maybe there's no way to do that? or any suggestions?
Thanks for the help!
I spoke with the support at Firebase and found a temporary solution, and a real solution.
Real solution: Manage the user and their password manually in all environments, using Firebase as "Database". That was basically what I was trying to do with my question. That resolve in using Firebase custom auth.
Temporary solution: (And what I did as I do not need as much security as the real solution offers)
Get something that identify the current user. Here I can get the current user email without even asking him.
Base64 the identifier:
byte[] result = System.Text.Encoding.UTF8.GetBytes(email);
email = Convert.ToBase64String(result);
Put, push, patch the required information via REST to firebaseio.com/Base64
In the user interface, that uses JavaScript, do the same process to read/write data at the user, using something like base64.min.js
var ref = new Firebase("https://aFirebase.firebaseio.com");
//Things happen
...
//We register a user
function createUser(email, password){
//Allows us to create a user within firebase
ref.createUser({
email : email,
password : password
}, function(error, userData){
if (error) {
//The creation of the user failed
alert(error);
} else {
//The creation of the user succeeded
console.log("Successfully created user account with uid:", userData.uid);
//We make sure we are at the correct position in our firebase
ref = ref.root().child(base64.encode(email));
//We check if the child exist
if(ref == ref.root()){
//The child doesn't exist
//We have to create it
user = {};
//Set the child with a value for the UID, that will fit with the rules
user[base64.encode(email)] = {uid:userData.uid};
//We set the new child with his value in firebase
ref.set(user);
}else{
//The child exist, we can update his information to go accordingly with our rules
ref.update({uid:userData.uid});
}
//Who wants to register and then not be logged in?
//We can add something upon login if his email is not validated...
login(email, password);
}
}
);
}
Now we have to update our rules in Firebase:
{
"rules": {
"$uid":{
".read":"!(data.child('uid').exists() == true) || data.child('uid').val() == auth.uid",
".write":"!(data.child('uid').exists() == true) || data.child('uid').val() == auth.uid"
}
}
}
With this, the application is somehow secure (as long as the user use the C# application and the JS application, where the rules will be set).
In case of a WebApi application a JWT token could be used along with OWIN pipeline.
app.UseJwtBearerAuthentication(new JwtBearerAuthenticationOptions
{
AuthenticationMode = AuthenticationMode.Active,
AllowedAudiences = new[] { FirebaseValidAudience },
Provider = new OAuthBearerAuthenticationProvider
{
OnValidateIdentity = OnValidateIdentity
},
TokenValidationParameters = new TokenValidationParameters
{
IssuerSigningKeys = issuerSigningKeys,
ValidAudience = FirebaseValidAudience,
ValidIssuer = FirebaseValidIssuer,
IssuerSigningKeyResolver = (arbitrarily, declaring, these, parameters) => issuerSigningKeys
}
});
Here is the sample of Firebase ASP.NET WebApi Authentication application: https://github.com/PavelDumin/firebase-webapi-auth

Token-based Authorization in Existing ASP.NET MVC App

I have inherited an existing application. This application uses ASP.NET MVC 3. It has some APIs. Those APIs look like the following:
[AcceptVerbs(HttpVerbs.Post)]
[Endpoint]
public ActionResult AuthenticatePlayer(string username, string password)
{
// Ensure that the user entered valid credentials
if (Membership.ValidateUser(username, password) == false)
return Json(new { statusCode = StatusCodes.INVALID_CREDENTIALS, message = "You entered an invalid username or password. Please try again." });
// Get the profile of the person that just logged in.
ProfileCommon userProfile = (ProfileCommon)(ProfileCommon.Create(username));
if (userProfile != null)
{
string name = username;
if (String.IsNullOrEmpty(userProfile.FirstName) == false)
name = userProfile.FirstName;
return Json(new {
statusCode = StatusCodes.SUCCESS,
payload = name,
username = username.ToLower(),
});
}
}
[AcceptVerbs(HttpVerbs.Get)]
[Endpoint]
public ActionResult SomeUserAction(string q)
{
// TODO: Ensure the user is authorized to perform this action via a token
// Do something
return Json(new { original = q, response = DateTime.UtcNow.Millisecond }, JsonRequestBehavior.AllowGet);
}
I'm trying to figure out how to integrate a token-based authorization schema into this process. From my understanding, a token-based system would return a short-lived token and a refresh token to a user if they successfully login. Then, each method can check to see if a user is authorized to perform the action by looking at the token. I'm trying to learn if this is built-in to ASP.NET MVC or if there is a library I can use. I need to figure out the shortest way to get this done.
Thank you so much!
I've built a WebAPI Token Authentication library a year ago, providing Token based authentication:
WebAPI Token Auth Bootstrap is out of the box Token based User Auth for WebAPI applications, Provides ready to use 'TokenAuthorize'
Attribute and 'TokenAuthApiController' Controller.
Among its features - Token Based User Authentication User Property inside the
TokenAuthApiController (Id, Username, Role, LastAccess).
Token Based User Authorization TokenAuthorizeAttribute with Access
Level - Public, User, Admin or Anonymous.
Built-in Functionality Login(), Logoff(), Error(), Unauthorized()
Responses with various overloads.
You can read more about here and in its own wiki in GitHub.
Nowadays I am working on a Node.js application and I am using Json Web Tokens (JWT) using Node.js library and it is very easy and straightforward.. its Node.js after all ;)
I saw there is a .NET implementation of JWT explained on this article which I recommend you to look at.
You can use Owin ... i.e. Microsoft.owin.security
I haven't tried this implementation but this is just to give you an idea:
var identity = new ClaimsIdentity(Startup.OAuthBearerOptions.AuthenticationType);
var currentUtc = new SystemClock().UtcNow;
ticket.Properties.IssuedUtc = currentUtc;
ticket.Properties.ExpiresUtc = currentUtc.Add(TimeSpan.FromMinutes(30));
DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
return Json(new {
statusCode = StatusCodes.SUCCESS,
payload = name,
username = username.ToLower(),
accessToken = Startup.OAuthBearerOptions.AccessTokenFormat.Protect(ticket)
});

Posting to FB Page error(s)

Scenario: I want to get user access token of the fb page admin by JS login and retrieving token ONE TIME, and will store that in database. Then daily, I want to do wall post to those page.
I am using JS to get the initial token and storing it. Then using c# FacebookSDK for the web requests.
FB.login(function (response) {
var r = response;
// get access token of the user and update in database
$("#FacebookAccessToken").val(response.authResponse.accessToken);
},
{
scope: 'manage_pages,publish_stream'
});
Now I am saving this token in database as I will be using this for future graph calls - is this right?
On server side when I need to do a post after a day I retrieve that token and do the processing as below:
// step 1 get application access token
var fb1 = new FacebookClient();
dynamic appTokenCLient = fb1.Get("oauth/access_token", new
{
client_id = appId,
client_secret = appSecret,
grant_type = "client_credentials",
scope = "manage_pages,publish_stream",
redirect_uri = siteUrl
});
var fbTokenSettingVal = GetTokenFromDB(); // getting access token from database which was stored during JS fb login
// step 2 extend token
var fb2 = new FacebookClient(appTokenCLient.access_token);
dynamic extendedToken = fb2.Get("oauth/access_token", new
{
client_id = appId,
client_secret = appSecret,
grant_type = "fb_exchange_token",
fb_exchange_token = fbTokenSettingVal.Val
});
var userExtendedToken = extendedToken.access_token; // get extended token and update database
// step 3 get page access token from the pages, that the user manages
var fb3 = new FacebookClient { AppId = appId, AppSecret = appSecret, AccessToken = userExtendedToken };
var fbParams = new Dictionary<string, object>();
var publishedResponse = fb3.Get("/me/accounts", fbParams) as JsonObject;
var data = JArray.Parse(publishedResponse["data"].ToString());
var pageToken = "";
foreach (var account in data)
{
if (account["name"].ToString().ToLower().Equals("PAGE_NAME"))
{
pageToken = account["access_token"].ToString();
break;
}
}
// step 4 post a link to the page - throws error !
var fb4 = new FacebookClient(pageToken);
fb4.Post("/PAGE_NAME/feed",
new
{
link = "http://www.stackoverflow.com"
});
The last 4th step throws error, when posting to selected page:
The user hasn't authorized the application to perform this action
Have tried several different ways, but in vain. Assume that there is just a simple step which I am doing wrong here.
Also, is it ok to extend the fb access token for user every time before making request?
Any way to check if token is expired or not?
If you want to use that access token for future. You need to take offline_access token and that token you need to store in database.
This offline accesstoken will be expire once user will change the password or delete your application from facebook account.
private void GetPermenentAccessTokenOfUser(string accessToken)
{
var client2 = new FacebookClient(accessToken);
//get permenent access token
dynamic result = client2.Post("oauth/access_token", new
{
client_id = _apiKey,
client_secret = _apiSecret,
grant_type = "fb_exchange_token",
fb_exchange_token = accessToken
});
_accessToken = result.access_token;
}
Looks like for new apps we need to apply for manage_pages permission from our application:
which I am doing now. As it shows error when doing login:
Also, the app needs to be live, so they can reproduce this permission and verify that we do need this permission to post to pages. Its good for fb users safety but a time taking process for developers.
Any way this can be skipped for testing purpose?

Get expire time of OAuth session

To grant or revoke access to my webapis, I use OAuth password- and tokenrefreshworkflow.
If I understand everything correctly the workflow should be something like this:
Authenticate with username / password / client id
Retrieve accestoken, refreshtoken and expire date
Start timeout in client to refresh your token after expired token time
Go on with bullet 2 -> and so on..
The progress above works fine so far. My problem is, that I don't get the expire time out of the users principle after the authentication request. So if I work with stateles webclients, I need to renew my token every request to retrieve a new expire date, even if the users token is valid :/
What I want is something like a /api/session/information service, that provides general information about the current session of an authenticated user.
How do I retrieve my expire date =)
[HttpGet]
[ActionName("information")]
public HttpResponseMessage Information(BaseRequest request)
{
var p = Request.GetRequestContext().Principal;
/* here i need help =) */
}
Just to expand on Henrik N.'s answer a little. If you're in C# then you can use JWTSecurityTokenHandler within System.IdentityModel.Tokens.Jwt (Nuget: Install-Package System.IdentityModel.Tokens.Jwt) to read the token and the resulting JwtSecurityToken object gives you some handy properties, one of which is ValidTo which converts the exp claim into a DateTime object for you E.g.:
var tokenString = GetTokenString(); // Arbitrary method to get the token
var handler = new JwtSecurityTokenHandler();
var token = handler.ReadToken(tokenString) as JwtSecurityToken;
var tokenExpiryDate = token.ValidTo;
// If there is no valid `exp` claim then `ValidTo` returns DateTime.MinValue
if(tokenExpiryDate == DateTime.MinValue) throw new Exception("Could not get exp claim from token");
// If the token is in the past then you can't use it
if(tokenExpiryDate < DateTime.UtcNow) throw new Exception($"Token expired on: {tokenExpiryDate}");
// Token is valid
Your access token (JWT?) should contain an expiry claim. In JWT it is "exp", which shows the number of seconds since 1970-1-1. In javascript you can get a date from this like this:
new Date(<exp> * 1000);
In .Net / C# you would be able to do the same:
var epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
return epoch.AddSeconds(<exp>);
Is that what you are looking for? Otherwise let me know. Happy to help :-)
You can use DateTimeOffset.FromUnixTimeSeconds:
var jwtExpValue = long.Parse(principal.Claims.FirstOrDefault(x => x.Type == "exp").Value);
DateTime expirationTime = DateTimeOffset.FromUnixTimeSeconds(jwtExpValue).DateTime;

Categories

Resources