Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add expires_at, to match OmniAuth auth schema #138

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions lib/omniauth/strategies/openid_connect.rb
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ class OpenIDConnect # rubocop:disable Metrics/ClassLength
},
code_challenge_method: 'S256',
}
option :expires_latency # seconds taken from credentials expires_at

option :logout_path, '/logout'

Expand Down Expand Up @@ -99,6 +100,7 @@ def uid
token: access_token.access_token,
refresh_token: access_token.refresh_token,
expires_in: access_token.expires_in,
expires_at: @access_token_expires_at,
scope: access_token.scope,
}
end
Expand Down Expand Up @@ -278,6 +280,11 @@ def access_token
@access_token = client.access_token!(token_request_params)
verify_id_token!(@access_token.id_token) if configured_response_type == 'code'

if @access_token.expires_in
@access_token_expires_at = Time.now.to_i + @access_token.expires_in
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we use the AccessToken#expires_at method with an expires_latency option?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess the tl;dr answer to your question is, "yes... should we?" 🙂

I don't think Rack::OAuth2::AccessToken has an #expires_at method... https://github.com/nov/rack-oauth2/blob/master/lib/rack/oauth2/access_token.rb, or am I looking in the wrong place? I could submit a PR for that upstream.

This is the question that I was referring to in the PR description:

I'm not sure if the best place to fix it is here or upstream, in
Rack::OAuth2::AccessToken. On the one hand, the oauth2 gem handles it in
OAuth2::AccessToken. On the other hand, the OmniAuth strategy is the only place we can
ensure minimal latency between the server response and expires_at computation. I chose
here. 🙂

That was the justification I gave on Dec 6th. But, in retrospect, I may have also been motivated to do it this way because it meant one PR in one repo rather than two in two repos. 😉

It makes intuitive sense to me that expires_latency should be an optional parameter to #expires_at, like you suggest. I think one benefit of applying expires_latency during construction might be that it allows code that uses access_token to remain naive, and thus simplifies application of a uniform policy. 🤷🏻 I don't feel strongly about it one way or the other, and I'll gladly apply expires_latency in the initializer (like the oauth2 gem), as an argument to the #expires_at method, or both.

What do you think? Should I make a PR to https://github.com/nov/rack-oauth2 first, and then update this PR after a new version is released there?

@access_token_expires_at -= options.expires_latency if options.expires_latency
end

@access_token
end

Expand Down
11 changes: 9 additions & 2 deletions test/lib/omniauth/strategies/openid_connect_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -697,6 +697,7 @@ def test_credentials
strategy.options.issuer = 'example.com'
strategy.options.client_signing_alg = :RS256
strategy.options.client_jwk_signing_key = jwks.to_json
strategy.options.expires_latency = 60

id_token = stub('OpenIDConnect::ResponseObject::IdToken')
id_token.stubs(:verify!).returns(true)
Expand All @@ -705,14 +706,20 @@ def test_credentials
access_token = stub('OpenIDConnect::AccessToken')
access_token.stubs(:access_token).returns(SecureRandom.hex(16))
access_token.stubs(:refresh_token).returns(SecureRandom.hex(16))
access_token.stubs(:expires_in).returns(Time.now)
access_token.stubs(:expires_in).returns(3599)
access_token.stubs(:scope).returns('openidconnect')
access_token.stubs(:id_token).returns(jwt.to_s)

client.expects(:access_token!).returns(access_token)
access_token.expects(:refresh_token).returns(access_token.refresh_token)
access_token.expects(:expires_in).returns(access_token.expires_in)

start = Time.now.to_i + access_token.expires_in - 60
creds = strategy.credentials
stop = Time.now.to_i + access_token.expires_in - 60
expires_at = creds.delete(:expires_at)
assert_includes start..stop, expires_at

assert_equal(
{
id_token: access_token.id_token,
Expand All @@ -721,7 +728,7 @@ def test_credentials
expires_in: access_token.expires_in,
scope: access_token.scope,
},
strategy.credentials
creds
)
end

Expand Down