S3 presigned urls are expiring too early - ruby-on-rails

The url is signed for 6 hours. The X-Amz-Date and X-Amz-Expires add upto the correct time. However, the url itself starts giving Access Denied errors several minutes before expiry time.
We're using aws-sdk-s3 for ruby, fwiw, in a kubernetes environment.

The problem was the our pods were using InstanceProfileCredentials. These are temporary, rotated credentials, which are also used to sign the urls we generate. So, if the current credential token is expiring in 4 hours, then the url will also be live for max 4 hours, even if we set a higher expiration time for url.
A bit of code to get the expiration of current token:
resource = Aws::S3::Resource.new(
region: 'us-east-1'
)
expiration = resource.client.config.credentials.expiration
# "2021-05-03T11:49:47.569+00:00"
This returns an instance of Time class. Based on this, we were able to calculate the max expiry we can set for a url and avoid 4xx errors.

Related

Using nodemailer & Google OAuth to send email, working for 7 days, but get invalid grant

I've been working to setup Oauth communication for an auto-emailing node.js web app using nodemailer. (I don't wish to use gmail's Less Secure Apps setting).
I've taken steps to get the client id, secret, and refresh token from the oauth playground, and have set up the web app to use a stored refresh token to request new access tokens when it first loads.
It is able to send emails (for about 7 days), then I get error invalid status code 400 on client side, and/or invalid grant on server side.
Going back to google playground and getting another refresh token, then updating it in environment variables, solves this for another week. But I'd like to solve this indefinitely.
I read somewhere "A Google Cloud Platform project with an OAuth consent screen configured for an external user type and a publishing status of 'Testing' is issued a refresh token expiring in 7 days"... so last week I switched the app to "In Production" (at console.cloud.google.com) and tried having it verified with google. This week, the same issue has recurred suggesting that wasn't the right fix, or that it wasn't yet verified with google.
I don't know if this was done correctly, nor do I know if this is the true solution to this expiring/revoked refresh token, or invalid grant.
I've also come across these explanations:
The user has revoked your app's access.
The refresh token has not been used for six months.
The user changed passwords and the refresh token contains Gmail scopes.
The user account has exceeded a maximum number of granted (live) refresh tokens.
The client has reached a limit of 50 refresh tokens per account if it's not a service account.
(I didn't make ANY changes during the week, so...not sure why these would have changed)
Is the issue the refresh token?
Or the status of the application?
Would it be dns/cname/cloudflare server issues?
For those who have the same issue in the future:
It turned out that google verification wasn't necessary.
It seems like the refresh token expiring after a week or 7 days was due to the placement of the oauth2Client.setCredentials() function call and accessToken variable.
Calling setCredentials() and obtaining the access token INSIDE the SendEmail() function (at runtime, just before sending email, rather than at application start/spinup time) seemed like it enabled the code to more dynamically generate the tokens it needed. After 12 days, it still seems like its working so I'd call this a success.
My guess at why it wasn't working before was because setting credentials outside of a function meant that code only ran once on server/application startup. It would then store the obtained access token in a const.
The access token would eventually expire, and even if called again/later inside of a function to obtain a new access token, it would be unable to change the value of a const property/variable, and so the call would inevitably fail after a week when it failed to renew.
Hope this helps anyone else having a similar issue.
My apologies for the run-on sentences.
There are a lot of causes for invalid grant it sounds to me like your refresh token is expiring.
If your project on google developer console is still in testing, has not been moved to published and has not gone though the google application verification process then refresh tokens have a max two week life span after which they will expire which may explain your invalid grant. The thing is there is no official word from google that this is happening its just what a lot of developers are seeing these days.
Another one is with gmail scopes if the user changes their password this will also cause the refresh token to expire.

How to set access token to expire in seconds

I have an issue to configuring Redhat Single SigOn (RHSSO) or Keycloak token expiration in seconds, about 30 seconds.
I just found the configuration in minutes. There is a way to adjust it to seconds?
From the Keycloak Admin Console it is not possible; Keycloak allows to specify the access token expiration time in Minutes, Hours or Days, but not in seconds:
Albeit, when one requests a token, the expiration time is display in seconds, namely:
{"access_token":"...","expires_in":60,"...}
The least amount of time that you can set via Admin Console is 1 minute. To be honest, I fail to see what would be the great benefit of having 30 seconds instead of 1 minute.
In the Admin Console, if one tries to specify 0.1 (or 0,1) minutes an error is displayed
Now that being said, it seems that you can use the Rest Full API to get around that restriction. First, request a token on behalf of the admin, extract its access token (let us called $ACCESS_TOKEN). And then call the following endpoint:
PUT <KEYCLOAK_HOST>/auth/admin/realms/<REALM_NAME>
with the following data
'{"accessTokenLifespan":30}'
Now if you request a token for a client on the Realm REALM_NAME you will get the following:
{"access_token":"...","expires_in":30,"...}
30 seconds as expiration time for the access token.
Now, I have not tested this, so it is up to you to find out if everything still works as it should.

How to permanently get the OneDrive API download address

https://learn.microsoft.com/en-us/onedrive/developer/rest-api/api/permission_delete?view=odsp-graph-online
Note: The #microsoft.graph.downloadUrl value is a short-lived URL and can't be cached. The URL will only be available for a short period of time (1 hour) before it is invalidated.
In the tutorial, the download url expires after an hour. How do I get a permanent download address?
error Message
Sorry, something went wrong
The access token has expired. It's valid from '11/11/2020 1:18:52 AM' and to '11/11/2020 2:18:52 AM'.
"The lifetime of an access token is 1 hour. Have you tried to use the refresh token to obtain a new access token, or customize the lifetime of the access token?"
Please try the same as suggested above by Carl. You need to use the refresh token to obtain a new access token or customize the lifetime of the access token. Here's the document.
Note: The #microsoft.graph.downloadUrl value is a short-lived URL and can't be cached. The URL will only be available for a short period of time (1 hour) before it is invalidated. Removing file permissions for a user may not immediately invalidate the URL.
The workaround was to create a share link for DriveItem and use the WebUrl as the result of the response.
The file was accessed and made available for download through WebUrl.
It seemed that the only way for non-tenant users to access it.

GitLab OAuth access token validity

Does anyone know what the expiration period of an OAuth Access Token on GitLab is?
It's at least 12 hours (from experience), but I would like to know for sure so I don't refresh the token unnecessary.
PS: GitLab ... it would be very convenient if the expiration is simply returned when getting/refreshing token (PS: the documentation states that "expires_in": is returned ... BUT IT ISN'T)
from https://forum.gitlab.com/t/missing-expires-in-in-the-token-response/1232/2:
Gitlab uses Doorkeeper for oauth.
The Doorkeeper wiki has an ariticle "Customizing Token Expiration" > https://github.com/doorkeeper-gem/doorkeeper/wiki/Customizing-Token-Expiration2
This wiki tells us a configuration "access_token_expires_in". I > searched in gitlab source code and found it sets to nil.
This meas the 'access_token' will never expire.
Also, this is from https://gitlab.com/gitlab-org/gitlab-foss/-/blob/50d66f5ece57dcfbe074d97703691a8d3c38f4ac/config/initializers/doorkeeper.rb#L42:
# Access token expiration time (default 2 hours).
# If you want to disable expiration, set this to nil.
access_token_expires_in nil
On GitLab, OAuth "access tokens expire in two hours".
Access tokens expire in two hours which means that integrations that use them must support generating new access tokens at least every two hours.
In older versions, OAuth applications could opt-out of access token expiry.
The ability to opt-out of expiring access tokens was deprecated in GitLab 14.3 and removed in 15.0. All existing integrations must be updated to support access token refresh.
2016: It should be 8 hours by default:
lib/gitlab/o_auth/session.rb mentions:
Rails.cache.write("gitlab:#{provider}:#{ticket}",
ticket, expires_in: Gitlab.config.omniauth.cas3.session_duration)
In gitlab.yml, you have:
# SSO maximum session duration in seconds. Defaults to CAS default of 8 hours.
# cas3:
# session_duration: 28800
2022: the Expiring access tokens documentation mentions:
no more opt-out of expiring access tokens since GitLab 15.0 (June 2022)
Access tokens expire in two hours which means that integrations that use them must support generating new access tokens at least every two hours.

Google OAuth's access token's expiry timezone

I recently switched to the Google+ Sign in OAuth2 hybrid approach.
When the request code is exchanged for the access token, the expiry time and created time is sent back along with the access token in seconds.
I need to know the sent timezone is. I need this to make comparison with my server's time and be able to deduce if access token has actually expired.
What's the timezone or how do I determine it?
The token bundle sent back does not include an actual expiration time, but it does contain the number of seconds for the expected life of the token. If a time is being attached to it, it is being attached by the local library.
That said - you can't necessarily trust this number. There are a number of reasons why the token may have been revoked or is treated as no longer valid. So while you can use it as an estimate of when you'll need to get a new one - you should also handle the case where you use a token and you get an authentication error, forcing you to refresh the token and try again.
My bad.
I just went through the Google PHP APi client library. Only to realize the created field was set within the library (on my server) in Google_Auth_OAuth2's authenticate method.
So it is safe to use $client->isAccessTokenExpired() instead to try to do one's computation. Works with local time (I guess :))
Thank you.

Resources