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.).
Related
I've a React JS app, which makes this request to my back-end API. i.e
window.location = "https://my-server.com" + "/gmail/add_account";
cannot set HTTP headers for window.location see this
this server endpoint redirects to Google OAuth page, which returns a response to my redirect_uri.
def add_account
# no auth headers sent here, because front-end has used window.location
gmail_service = GmailService.new
session[:uid] = params["uid"]
redirect_to gmail_service.generate_authorization_url()
end
def oauth_postback
# session object is {} here
# Since there are no authorization headers, I cannot identify my app's user
# How can I identify my app's user here?
end
The problem I'm facing is that when the OAuth flow sends the response to my redirect_uri it does not return include any authorization header, due to which I'm unable to identify which user of my app has launched this OAuth flow.
I've tried setting up a session variable in the /gmail/add_account endpoint, which works fine. After this endpoint redirects to the OAuth screen, and the Oauth flow sends a response to my Oauth redirect_uri, there my session object is {}.
How can I implement this flow such that I know which user has launched this OAuth flow?
You have basically two options:
the state parameter
The state parameter is part of the OAuth2 spec (and is supported by Google). It's a random string of characters that you add to the authorization URL (as a query parameter), and will be included when the user is redirected back to your site (as a query parameter). It's used for CSRF protection, and can also be used to identify a user. Be sure that if you use it, it's a one-time value (e.g. a random value that you store in your db, not the user's ID).
sessions with cookies
If the user has previously logged in, you should be able to identify them by their session cookie. It sounds like this is the approach you're currently taking, but the session is getting reset.
It's difficult to debug this without knowing more about your stack/code, but a good first step would be just trying to load your callback URL without the redirection to Google to see the session object is still empty. If so, that would indicate an issue with how you've implemented sessions generally and not something specific to this flow.
As a note, based on the code you've shared, I'm not sure how params["uid"] is getting set if you're doing a redirect without any query parameters or path parameters.
Finally, you may consider using a managed OAuth service for something like this, like Xkit, where I work. If you have a logged in user, you can use Xkit to connect to the user's Gmail account with one line of code, and retrieve their (always refreshed) access tokens anywhere else in your stack (backend, frontend, cloud functions) with one API call.
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.
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).
Hey guys I'm trying to use the Dailybooth api, and getting access to the user via oauth.. I'm very new to ruby/rails and this is my first time working with an api and oauth. Here's the thing though
if params[:code] #if the code is avaible, use the code
dailybooth.oauth_token(params[:code])
#oauth_token_ = params[:code]
session[:oauth_code] = #oauth_token_
else #else, attempt to use the session
if session[:oauth_code] #If session is set
dailybooth.oauth_token(session[:oauth_code]) #sign in using session
else #else, check if the params[:code] is set and use, or redirect to dailybooth authorize
if params[:code]
dailybooth.oauth_token(params[:code])
#oauth_token_ = params[:code]
session[:oauth_code] = #oauth_token_
else
#first redirect the user to the authorize_url
redirect_to dailybooth.authorize_url
end
end
end
#make request to the api
#info = dailybooth.get('/users.json')
if #info['error']
if #info['error']['error_code']
if #info['error']['error_code'] == 302 #if getting invalid token, request another token.
session[:oauth_code] = nil
#info = "Getting Errorcode 302, invalid token."
#first redirect the user to the authorize_url
# redirect_to dailybooth.authorize_url
end
end
end
So, that is the index of my app. When I first go to the index, I'm immediatly transfered to dailybooth to authorize my account, after authorizing, dailybooth returns me to my site with a URL that looks like so "http://site.com/?code=XXX" and "dailybooth.get('/users.json')" goes to work, it actually get's the user information. but if I try to refresh, going to the same "http://site.com/?code=XXX" it'll say the token is invalid. Why is that? The token was just valid and now it's not working. Any suggestions? Is this an error on my end?
My guess is that the problem is you are storing the dailybooth OAuth Token and not the Access Token. Your call to dailybooth.oauth_token(...) probably generates an Access Token and you should be storing that, not the params[:code] (OAuth Token). Generally OAuth works like this:
The user is redirected to the site to give your application access.
The user is redirected back to your site with an OAuth Token giving you access to certain parts of the API or external site.
You trade that OAuth Token in for an Access Token that you can use to access the API and site at any time.
Once that OAuth Token has been traded in for an Access Token it can't be used again, but the Access Token can.
Check the dailybooth object, you can probably access the actual Access Token somehow (dailybooth.token or dailybooth.access_token maybe?). Make sure you store that access token in your session or database, and then use that access token upon returning to the page instead of the params[:code] that has at this point become invalid.
I cannot help you with Ruby as I've never used it, however I can add to the comment above what is the flow in OAuth 2 (which is definitely the preferred choice to use):
The user goes to your site and needs to access functionality that requires the use of a Third-Party OAuth provider API (your site is Consumer and the Third Party is Provider and I will call them this way below)
Consumer makes internal HTTPS request to the Provider to get unauthorized Request token.
Consumer redirects the user to the Provider with the Request token it just received in step 2, in order for this token to be authorized by the user at the Provider's site.
After the user authorize the Request token (eventually), the Provider creates Verifier String and redirects the user back to the callback with this Verifier String and the Request Token, which is very important. In fact, this is the part of OAuth 2, which identifies that the user has really authorized the token (the Verifier String).
Consumer makes internal HTTPS request with the Request token and this Verifier String to get Authorized Access Token.
At this point if the Consumer receive Access Token, he has the right to access the protected API with the user's permission.
Here is a good explanation of why the Verifier is important and added to the protocol:
http://hueniverse.com/2009/04/explaining-the-oauth-session-fixation-attack/
I'm learning about OAuth with the goal of allowing visitors to my website the ability to sign in with Twitter. I've been using the Python based oauth2 library as a learning tool, and I think I get most of it.
I understand that after the user authenticates with the service (Twitter in this case) the user is sent to the callback URL with the parameters oauth_token and oauth_verifier.
What I fail to understand is the proper way of storing this information in the users browser. How do I identify these values during subsequent requests? Am I required to create a session system as with a normal website, or is there some magic in OAuth that makes this unnecessary?
How you handle client sessions of people who visit your website is not covered by OAuth, that remains up to you (and the usual session management frameworks).
All OAuth does is tell you that the user really is the Twitter user he claims to be. You can then associate this piece of information with the user session on your site (just like you would if the login screen was on your own page).
there are two types of oauth_token and oauth_verifier in twitter API
first is request token that always come different on each process, that can be save into session using getRequestToken method
i m telling in PHP view , but logic are same in any language
/
* Get request token */
$request_token = $connection->getRequestToken(OAUTH_CALLBACK);
/* Save request token to session */
$_SESSION['oauth_token'] = $token = $request_token['oauth_token'];
$_SESSION['oauth_token_secret'] = $request_token['oauth_token_secret'];
another is accesstoken: that is retrived via getAccessToken method
$access_token = $connection->getAccessToken($_REQUEST['oauth_verifier']);
Array
(
[oauth_token] => 223961574-mEctH7SHai######
[oauth_token_secret] => G7Buyxn4okF31Ln3ulAh#####
[user_id] => 223961574
[screen_name] => ltweetl
)
these token are same which is in your registered application on twitter
and already given at below page...
http://dev.twitter.com/apps/{your_app_id}/my_token.