I have started using spring session in my jersey rest api, is there a way we can renew the expired session token . I know that we are deleting the token as soon as it ttl is over but is there any way I can achieve this. Any help is highly appreciated . Thank you so much
This is how we solved this problem:
Based on username & password we are getting access token+refresh token. Mention grant type is password in this case.
We are saving token in session.
[access token] as key and [accesstoken, UserDetails, RefreshToken and expiryTime] as value.
Each time a reuest is coming to the server, we are checking the expiry time in the session with the current system time.
Once a token is expired. InvalidTokenException is thrown.
Catch the exception in the front end and send another request with acesstoken + refresh token + grantType="refresh_token".
Then we are checking if refresh is there in the session or not. If yes, we issue a new token and update expiry time.
Please refer this image.
Related
I'm using the AppleAuth npm package in my server to submit token requests to Apple's servers during the sign in with Apple process. (This is based off the sample server code provided with the sign_in_with_apple package in pub.dev) I have no issues submitting the authorization code to get my first access and refresh tokens.
However, when trying to test how my app would get a new refresh token, when I submit a POST request to https://appleid.apple.com/auth/token with the grant_type set to refresh_token the response I get is different than from having the grant_type set to authorization_code.
I looked at the source code of the package, and for its AppleAuth(myConfig).refreshToken(myRefreshToken) (<- pseudo code lol) the only difference in the POST payload is:
{
grant_type: 'refresh_token', // instead of grant_type: 'authorization_code'
refresh_token: refreshToken, // instead of code: authorizationCode
... // other params
}
While the initial request with authorization code returns both an access token and a refresh token, for some reason the refresh token request is only returning the access token. I really don't think it's the package causing the error, nor can I see how my code would be the source either, since the above code is the only difference.
I tried passing the access token that it returns in a new refresh token request in order to test that I can get new refresh tokens whenever necessary in the future, but it returns a 400 status error.
Am I missing something here? Is there a reason the refresh token request returns no new refresh token? Or am I missing something entirely about how the process/flow is supposed to work? I am trying to do this for the "check the refresh token once daily to confirm the user is still in good standing with Apple's servers" part of the process.
I've really been stuck on what to do at this point. I can save the identity_token.sub field in my database to check whether my user is signed in, but of course I want to make sure my user's apple ID is still valid with apple, and that they haven't revoked access. Could it be that because I tried to get a new refresh_token too soon Apple only returned the access_token?
Oh also, the app itself is a Flutter app and I am testing all of this on my iPhone 11 so it's not an Android/Web flow.
Whether you get a new 'rolling / rotating' refresh token in a refresh token grant response is generally vendor specific:
You may get a new refresh token occasionally but not always
The primary purpose of this message is to get a new access token, not a new refresh token
In terms of token handling, the client should update its tokens similarly to the saveTokens method in this sample of mine.
I've not used Sign In with Apple but I suspect proceeding as follows would be the simplest solution:
Keep access tokens short lived: no more than 60 minutes
This forces a frequent token refresh, which by default is very quick
If the user's Apple Id is revoked I would expect this to return an invalid_grant response
We are creating an application with Ionic framework as front-end and Ruby on Rails as back-end. We are able to link Gmail account in our app. Account linking is working fine, we get serverAuthCode from front-end and then using that we get refresh token and we are able to fetch emails with that refresh token at first attempt. But within seconds, it get expired or revoked. Getting the following issue:
Signet::AuthorizationError (Authorization failed. Server message:
{
"error" : "invalid_grant",
"error_description" : "Token has been expired or revoked."
})
It seems like, refresh token itself is expiring in seconds. Does anyone have any idea about how to fix it?
Update:
Existing code looks like this:
class User
def authentication(linked_account)
client = Signet::OAuth2::Client.new(
authorization_uri: 'https://accounts.google.com/o/oauth2/auth',
token_credential_uri: Rails.application.secrets.token_credential_uri,
client_id: Rails.application.secrets.google_client_id,
client_secret: Rails.application.secrets.google_client_secret,
scope: 'https://www.googleapis.com/auth/gmail.readonly, https://www.googleapis.com/auth/userinfo.email, https://www.googleapis.com/auth/userinfo.profile',
redirect_uri: Rails.application.secrets.redirect_uri,
refresh_token: linked_account[:refresh_token]
)
client.update!(access_token: linked_account.token, expires_at: linked_account.expires_at)
return AccessToken.new(linked_account.token) unless client.expired?
auth.fetch_access_token!
end
def get_email(linked_account)
auth = authentication(linked_account)
gmail = Google::Apis::GmailV1::GmailService.new
gmail.client_options.application_name = User::APPLICATION_NAME
gmail.authorization = AccessToken.new(linked_account.token)
query = "(is:inbox OR is:sent)"
gmail.list_user_messages(linked_account[:uid], q: "#{query}")
## Getting error over here ^^
end
end // class end
class AccessToken
attr_reader :token
def initialize(token)
#token = token
end
def apply!(headers)
headers['Authorization'] = "Bearer #{#token}"
end
end
Reference link: https://github.com/google/google-api-ruby-client/issues/296
From what I can guess the issue seems to be on these two lines. The way token expiry is being checked and the new token is being generated. It would be great if there is minimal reproducible code.
return AccessToken.new(linked_account.token) unless client.expired?
auth.fetch_access_token!
Here is how I get my access token:
def self.access_token(refresh_token)
Cache.fetch(refresh_token, expires_in: 60.minutes) do
url = GoogleService::TOKEN_CREDENTIAL_URI
# p.s. TOKEN_CREDENTIAL_URI = 'https://www.googleapis.com/oauth2/v4/token'
_, response = Request.post(
url,
payload: {
"client_id": GoogleService::CLIENT_ID,
"client_secret": GoogleService::CLIENT_SECRET,
"refresh_token": refresh_token,
"grant_type": "refresh_token"
}
)
response['access_token']
end
end
And then use this access token for any purpose. Let me know how it goes and also if you are able to create a reproducible version of the API. That will be great.
Have you tried refreshing the access token with the refresh token? You can catch the error and retry.
Something like this:
begin
gmail.list_user_messages(linked_account[:uid], q: "#{query}")
rescue Google::Apis::AuthorizationError => exception
client.refresh!
retry
end
Not enough code is posted, but what is posted looks wrong.
linked_account is not defined
Nowhere is it shown that linked_account.token is ever updated (or set, for that matter). It needs to be updated when the refresh_token is used to get a new access token.
auth appears to be undefined in the line auth.fetch_access_token!
GmailService#authorization= takes a Signet::OAuth2::Client not an AccessToken.
Probably what is happening is that you have a valid access token in linked_account.token until you call client.update!, which fetches a new access token and invalidates the old one. But since you never update linked_account, future calls fail until you go through the code path that resets it.
You only need to call client.update! if the access token has expired, and if it has expired and you get a new one, you need to store that new one in linked_account.token.
The thought that the refresh token will never expire is actually a misunderstanding. The actual scene is that the server issues a short-lived access token and a long lived refresh token. So in reality what happens is that the access token can be regained using the long lived refresh tokens but yes, you will have to request a new refresh token (as it expires too !). For example; you may treat refresh tokens as if they never expire. However on sign-in check for a new one, in case the user revokes the refresh token, in this scenario, Google will provide a new refresh token on sign-in so just update the refresh token.
Now the condition can be that the user revokes access to your application. In this case, the refresh token will expire (or I should actually say that it would become an unauthorized one). So if that is the scenario in your case, you will have to think on avoiding the revoking of access for the application.
For better understanding of it, you may refer to this document and even OAuth 2.0 documentation.
There are several reasons why a refresh token would stop working.
It gets to old refresh tokens expire after six months if not used.
A user can reauthecate your application and get a new refresh token both refresh tokens will work you can have a max of fifty outstanding refresh tokens then the first will stop working.
the user can revoke your access.
Wakey daylight savings time bug of 2015. (we wont talk about that)
Gmail and reset password.
This is mostly like due to a password reset. OAuth grants with the gmail scopes are revoked when a user changes their password.
See Automatic OAuth 2.0 token revocation upon password change
In general, users can revoke grants at any time. You should be able to handle that case gracefully and alert the user that they need to reauthorize if they wish to continue using the functionality provided.
You have been doing a lot of testing i would guess are you saving the newest refresh token? If not then you may be using old refresh tokens and the will stop working. (number 2)
In my case, only youtube upload api raise
Unauthorized (Google::Apis::AuthorizationError)
and other api, like list videos api work well
it's because i use new google account and have not up video
i manually up video in youtube web, youtube require me create "channel"
and I try youtube up api again, it work
I guess it's because youtube has channel to up
I have session timeout setting as 1 hours, and my initial access_token seems timeout around this time. This is excepted.
And after it timeout, i did token refresh and get a new access_token, then i observed this refreshed access_token seems not timeout in 1 hours, even 5~6 hours after, it still not expired.
So is there refresed access_token never expire? Can someone explain more about this?
Refresh token policy is managed from admin side usually and is different from the initial access token. From what you say the setting you have right now for Refresh token is probably 'Refresh token is valid until revoked'.
When you go to your Salesforce org go to Setup -> Manage Connected Apps - find the connection you are looking for and see what policy you have set. You can set it to expire in number of days, based on usage or Immediately.
I want to generate a new Capability Token whenever the existing Token expires using Twilio.Device's offline handler.But this is triggered even when the connection is dropped.
Is there any way to know whether the Twilio.Device.offline(handler()) is triggered due to the expiry of Capability Token alone.
While I don't think there's a way to only trigger Twilio.Device.offline(handler()) when a token expires, you can ensure token expiry by checking for Error 31205 JWT Token Expired.
Upon log of this error you can then handle it in your application as you see fit.
A client credential grant does not return a refresh token (DotNetOpenAuth.OAuth2.AuthorizationServer.PrepareAccessTokenRequest forbids it). But ClientBase.AuthorizeRequest requires it.
Is this a bug in DotNetOpenAuth or am I doing something wrong?
I suppose I can work around by inheriting ClientBase and overriding AuthorizeRequest. Is that the correct thing to do?
Edit: It's not so easy to inherit from ClientBase outside of DotNetOpenAuth because a lot of the stuff you want is internal only. e.g. ErrorUtilities.VerifyProtocol
Edit2: Just read the draft OAuth 2 spec (draft 25) referred to in DotNetOpenAuth.OAuth2.AuthorizationServer.PrepareAccessTokenRequest and I can't find where it disallows refresh tokens for Client credential grant type. Maybe they changed it?
Google returns Refresh Token if you request it. Provide parameter in query string access_type=offline.
In my case I had to amend default Authorization Endpoint URL to: https://accounts.google.com/o/oauth2/auth?access_type=offline
Google Api C# example using DotNetOpenAuth:
private WebServerClient GetClient()
{
return new WebServerClient(
new AuthorizationServerDescription
{
AuthorizationEndpoint = new Uri("https://accounts.google.com/o/oauth2/auth?access_type=offline"),
TokenEndpoint = new Uri("https://accounts.google.com/o/oauth2/token"),
ProtocolVersion = ProtocolVersion.V20,
},
clientIdentifier: this.settings.GoogleApisClientIdentifier,
clientSecret: this.settings.GoogleApisClientSecret
);
}
NOTE from my experience: This works only for the First request.
See Google Documentation.
I'm not sure why you say that ClientBase.AuthorizeRequest requires it. Firstly, there is an overload that only takes an access token, so it doesn't even ask for a refresh token. The overload you may have tried accepts an IAuthorizationState object, which may or may not include a refresh token, and it appears that that method only looks for a refresh token if the access token has expired. Since an expired access token can't be used, it tries to refresh it and throws if it can't. It seems reasonable to me.
Whichever method overload you choose to call, your calling mode must either avoid using expired access tokens or be prepared to respond to the exceptions that are thrown when DotNetOpenAuth or the resource server determines that they are expired or revoked. In fact since tokens can be revoked before they expire, it's a good idea to always be prepared for that.
The OAuth 2 spec draft 25 does in fact indicate that a refresh token should not be included in a response to the client credentials grant. From section 4.4.3:
4.4.3. Access Token Response
If the access token request is valid and authorized, the authorization server issues an access token as described in Section 5.1. A refresh token SHOULD NOT be included. If the request failed client authentication or is invalid, the authorization server returns an error response as described in Section 5.2.