ueberauth/guardian

"token_expired" error handling uniformisation between VerifyCookie and VerifySession

quaresc opened this issue · 8 comments

Hello !

I’ve encountered an incoherence between VerifyCookie and VerifySession for a token_expired error.

VerifyCookie ignores it whereas VerifySession does not and I think it complexifies some pipelines.

This incoherence has been raised here #517

VerifyCookie:

{:error, :token_expired} ->

VerifySession:

{:error, reason} ->


An exemple where this difference is problematic:
I implemented the remember_me function in order to create a refresh token alongside a session cookie with my access token in it.
If my access token is expired, I would like to check if a refresh exists/valid to exchange it for an access token.

To handle such case, I have to ignore the halt in Guardian.Plug.VerifySession which will allow Guardian.Plug.VerifyCookie to be called but also handle this error directly in my error_handler (could be handled in ensure_authenticated plug in some cases).


 plug(Guardian.Plug.VerifySession, claims: @claims, halt: false)
 plug(Guardian.Plug.VerifyCookie)
def auth_error(conn, {:invalid_token, :token_expired}, _opts) do
  conn
end



Wouldn’t be best to uniformise both plugs or at least provide an option ?


Maybe my pipeline isn't coherent, feel free to tell me :) !

So the VerifyCookie should look if your access_token has expired and if so use the refresh_token in the cookie to get a new access_token. If you swap your two plugs I think everything should work as excepted. Is there something I am missing?

 plug(Guardian.Plug.VerifyCookie)
 plug(Guardian.Plug.VerifySession, claims: @claims)

Maybe we should make this more obvious in the docs

If I swap my two plugs, I believe that it will first check my refresh_token instead of my access_token

Yea, I guess it will always do the exchange. I am wondering how other people have set up their pipelines.

I guess it would make sense if VerifyCookie checked if the current session token was valid and then just used it?

Exactly and I couldn't really find other pipelines with a similar use case with refresh and access tokens (expect in the linked issue)

I guess it would work but it would do exactly the same job of VerifySession which might be a little confusing + if you don't use session tokens, wouldn't it be an unnecessary check ?

Yea, so I think the problem comes down to that you could have a pipeline looking like this

plug(Guardian.Plug.VerifyHeader, claims: @claims, halt: false)
plug(Guardian.Plug.VerifySession, claims: @claims, halt: false)
plug(Guardian.Plug.VerifyCookie)

Where you want to get token from the header if is there, else
Get it from the session, else
Get it from the cookie

So I guess we could let the VerifyHeader and VerifySession parse through if the token has expired.
But then we will not be able to handle this case in the error handler, but maybe this is okay since it will get handled in ensure_autenticated

As previously mentioned this would be a breaking change. As some could rely on the VerifySession throwing the Token expired error. What do you think @ueberauth/developers

VerifyCookie being not really useful in this pipeline on its own, one alternative could be to implement an option to VerifyHeader and VerifySession like verify_cookie: true which will check and exchange the cookie directly (and avoid a breaking change)

Well the verify cookie as of now actually just uses the refresh_token to generate the access_token on every request if you don't have the VerifySession in front.

I think it would actually make sense to have an option to both verify header and session to refresh from a cookie, instead of it being a plug itself. I have always been confused about the verify cookie anyways since it sounds like it will look up an access token there.

My current suggestion would be to deprecate VerifyCookie and add options to verify header and session to reauth from a refresh token in a cookie.