WIF session token set through SessionAuthenticationModule lifetime - wif

Please help me to understand the concept of expiry time for sessiontoken.
Below is the way I am setting the session token after receiving the token from STS.
var principal = validationfunction();//returns claimsprincipal
if (principal != null)
{
var token = new SessionSecurityToken(principal.ClaimsPrincipal)
{
IsReferenceMode = false
};
//this makes sure that the identity and claims are written to the cookie.
FederatedAuthentication.WSFederationAuthenticationModule.SetPrincipalAndWriteSessionToken(token, true);
}
Please confirm if this is true or not:
if the token lifetime is 10 mins. if user is inactive for 10 mins and doesnt send any request to
website it the session token expires and its redirected to STS login page.
if user is active and keep refreshing the page/visits different page the sessiontoken lifetime gets
refreshed . it means everytime the user visits the page the token gets new expiry value. So user will not be redirected to login page every 10 mins.
if user requests a STS protected resource (web api) , the life time of token is treated absolute. Meaning regardless user is active or not, after 10 mins of token generated if the user requests web api , the token will be invalid and redirected to STS login page.
are the above concepts correct?

You need to set the token lifetime yourself. The default is IIRC - 10h. When the token has expired and you are accessing a protected resource, the application will emit a 401. If you have the WsFed modue - this will result in a roundtrip to the STS
Session security tokens are absolute expiration by default
You wouldn't use a cookie to secure a Web API - a redirect does not make sense for APIs (nor does cookie authentication).

Related

Re-authorization for an app to send gmail

under what situations (other than someone revoking permission of changing their gmail password) would a user need to re-authorization an app's access to their gmail data? My app stores and uses a refresh token to maintain a current access token, but my users are occasionally still asked to authorize from scratch, and sometimes this then fails and only works again when they reset their browser settings.
Causes for a refresh token to expire.
user revokes access.
User changes password and your using a gmail scope
refresh token has not been used in six months.
You can have a max of 50 outstanding refresh tokens for a user. So if the user is requesting a new refresh token often make sure to store the newest as the once you hit 51 the oldest one available will be expired.
That should be about it unless you consider the bug of fall 2015 which caused a bunch of refresh tokens to expire due to daylight savings time. (That was a fun day)
I'm not storing anything explicitly, it's all being done by Google's Authorization Broker. Here's the code:
UserCredential credential;
using (FileStream credentialsfile = new FileStream(Application.StartupPath + #"/credentials.json", FileMode.Open, FileAccess.Read))
{
string credPath = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
credPath = Path.Combine(credPath, ".credentials/SJGmailAPI.json");
credential = GoogleWebAuthorizationBroker.AuthorizeAsync(GoogleClientSecrets.Load(credentialsfile).Secrets, Scopes, senderemailaddress, CancellationToken.None, new FileDataStore(credPath, true)).Result;
}
bool rc = AuthTest.TestAuthorisation(credential,senderemailaddress,ApplicationName);
So is Google's own code storing the wrong refresh token then?

Google OAuth2 refresh expires & does not renew

I followed this tutorial EXACTLY, however
#app.route('/test')
def test_api_request():
if 'credentials' not in flask.session:
return flask.redirect('authorize')
# Load credentials from the session.
credentials = google.oauth2.credentials.Credentials(
**flask.session['credentials'])
drive = googleapiclient.discovery.build(
API_SERVICE_NAME, API_VERSION, credentials=credentials)
files = drive.files().list().execute()
# Save credentials back to session in case access token was refreshed.
# ACTION ITEM: In a production app, you likely want to save these
# credentials in a persistent database instead.
flask.session['credentials'] = credentials_to_dict(credentials)
return flask.jsonify(**files)
However in this part:
credentials = google.oauth2.credentials.Credentials(
**flask.session['credentials'])
The refresh token expires after an hour, with this error:
The credentials do not contain the necessary fields need to refresh the access token. You must specify refresh_token, token_uri, client_id, and client_secret.
But clearly in the flask session the dict object is there:
{'client_id': '<COMMENTED_OUT>.apps.googleusercontent.com',
'client_secret': '<COMMENTED_OUT>',
'refresh_token': None,
'scopes': ['https://spreadsheets.google.com/feeds',
'https://www.googleapis.com/auth/drive',
'https://mail.google.com/'],
'token': '<COMMENTED_OUT>',
'token_uri': 'https://oauth2.googleapis.com/token'}
I believe the google tutorial auto-refreshes the token
Two questions
1) Do i need to manually "refresh" the refresh token? The comment in the tutorial says "Save credentials back to session in case access token was refreshed".. which implies that it's refreshed automatically
2) Is this because the app is still in unverified status?
Looking at the dict, the refresh token is missing:
'refresh_token': None,
You need this token in order to refresh your access token after it expires. The refresh token is only provided in the JSON response if the user saw a consent screen (the one that lists the scopes being requested). If the user has previously approved access, and the scopes haven't changed, the OAuth flow will skip that screen if the user is sent back into the flow, and therefore not return the refresh token.
What likely happened is that during your testing you approved access once, but didn't store the refresh token correctly. Further attempts to approve access didn't return the refresh token, hence your inability to refresh the access token.
To ensure a refresh token is always returned, set the URL parameter prompt=consent in the authorization URL:
authorization_url, state = flow.authorization_url(
access_type='offline',
include_granted_scopes='true'
prompt='consent')
(It's documented in the "HTTP/REST" tab here).
Alternatively, visit and revoke access to your application. The next time you go through the OAuth flow you should see the consent screen again, and get a new refresh token.

Refresh token with Twitter API

I'm wondering if Twitter has an API endpoint that exchanges an expired access token with an active one. The way that I have the login flow working right now goes something like this.
// Request a token and redirect to the authorization page
$token = $this->twitter->getRequestToken();
// Set the session data
$this->session->set_userdata('oauth_token', $token['oauth_token']);
$this->session->set_userdata('oauth_token_secret', $token['oauth_token_secret']);
// Redirect the user to the authorization page
header('Location: https://api.twitter.com/oauth/authorize?oauth_token='.$token['oauth_token']);
The page that the user is redirected to will prompt the user to authorize my app each and every time they want a valid access token. Upon accepting the authorization, the user will be redirected to the callback URL. At my callback URL, the following happens
// Get the parameters from the URL
$token = $this->input->get('oauth_token');
$verifier = $this->input->get('oauth_verifier');
$oauthToken = $this->session->oauth_token;
$oauthSecret = $this->session->oauth_token_secret;
// Get the access token
$access = $this->twitter->getAccessToken($verifier, $oauthToken, $oauthSecret);
Does such a way exist for an access token to be generated without having to authorize my app each and every time?
According to Twitter's OAuth FAQ, tokens don't expire unless a user explicitly rejects your application or an admin suspends your application.
If you want your users to be able to login repeatedly without having to reauthorize, you'll need to come up with a mechanism for storing the tokens (cookies, database, etc.).

FedAuth cookie does not display expiry date in Firebug

I have an ASP.Net MVC site secured with SSL and am using System.IdentityModel.Services and am creating the token like this:
SessionSecurityToken token = new SessionSecurityToken(myClaimsPrincipal, TimeSpan.FromDays(1));
SessionAuthenticationModule sam = FederatedAuthentication.SessionAuthenticationModule;
sam.WriteSessionTokenToCookie(token);
When I access the site in the browser, Firebug does not display the expiry date as expected. Instead the expiry date is shown as Session:
Can anyone explain why this is please? I assume that ASP.Net can still see the actual expiry date internally when it reads the cookie? More so, where is the cookie expiration time actually set?
You're mixing two different things here:
Token Expiration is determining until when the token is valid. After that time, even if the token is attached to a request, it is considered invalid and will not be honored. Usually the expiration time is encrypted within the token itself and that means that it's controlled solely by the token issuer.
Cookie Expiration is something that is controlled by the client (your Web-Browser in this case). Once the Cookie is expired it is no longer being attached to the request. But, should the Browser decide to send it, it will work until the Token expiration has reached.
In your particular case, the Token expiration is set to 1 day, but since the Cookie expiration is set to 'Session' it means that if you were to end the session (typically by closing your Browser window) at some point before the Token expires, the Cookie will not be sent and you'll be required to login again.
After 1 day (when the Token expires), even if you're still in session, you're always required to login again.
Update (as per your comments):
Ticket expiration and Cookie expiration can be set separately simply because sometimes the ticket is not necessarily contained in a Cookie. It may be sent to the server using other methods (QueryString, custom HTTP header etc). Yet, indeed the natural thing to do is have them both set to the same expiration time.
This is also the case in your SessionSecurityToken, if you'll set its IsPersistent flag to true you'll notice that Cookie expiration is now the same as the Ticket:
SessionSecurityToken token = new SessionSecurityToken(myClaimsPrincipal, TimeSpan.FromDays(1));
token.IsPersistent = true;

Update bearer token without logging out and in again using WIF

Quick summary... Here's a pseudo-flow to show what I'm trying to accomplish...
Client (angular) -> Server (webapi/WIF)
Log in with username and pwd -> Validate login credentials and return bearer token with claims
Change selected client -> Send new bearer token with updated claims based on selected client
When changing selected client, the existing bearer token will of course be sent, so the server can use that to know who I am and verify I can change to the selected client before generating a new bearer token to return
More detail...
I am using the default code generated by WIF to log users in and return a bearer token that is then sent with every request from my app (angular). I call the TOKEN endpoint with my username and password, GrantResourceOwnerCredentials is called, the user is authenticated, the claims are set, and the access_token is returned. All well and good.
Here's the scenario I don't know how to handle. When the user is logged in, they have the claims for the default client to which they are assigned. However, they can change the client they're accessing at any time while logged in, but each client comes with its own set of claims, meaning that the bearer token needs to be replaced with one for the selected client.
I keep thinking there's a "public string ReturnNewBearerToken(AuthenticationTicket ticket)" function somewhere that would let me get a new token and return it as a string. But I've scoured the web and can't find anything to do this. Everything I've seen suggests that you have to log out and log back in to update your token, which I can't believe is the case. I can't know what client the user wants to access the app as until the log in, but once they're logged in I can't update the token? That would be a catch 22.
So, does anyone know how to do this with WIF?
The answer is in my comments above. The jist is that the line...
var tokenStr = Startup.OAuthOptions.AccessTokenFormat.Protect(ticket);
is what I needed to be able to return an encoded ticket as a bearer token to my angular app.

Resources