shaj13 / go-guardian

Go-Guardian is a golang library that provides a simple, clean, and idiomatic way to create powerful modern API and web authentication.
MIT License
543 stars 55 forks source link

Feature: Access token, Refresh token, OAuth2 #113

Closed IzioDev closed 2 years ago

IzioDev commented 2 years ago

Hi,

I am currently using the jwt strategy for development process. This works good so far, however, I can see there is some caveats:

I think creating a new strategy like refreshTokenStrategy will resolve these issues.

There is a full specification of the OAuth2 here: https://datatracker.ietf.org/doc/html/rfc6749

Protocol Flow: https://datatracker.ietf.org/doc/html/rfc6749#section-1.2

What is a refresh token: https://datatracker.ietf.org/doc/html/rfc6749#section-1.5 What is an access token: https://datatracker.ietf.org/doc/html/rfc6749#section-1.4

Authorization code grant: https://datatracker.ietf.org/doc/html/rfc6749#section-4.1 Resource owner Password credentials grant: https://datatracker.ietf.org/doc/html/rfc6749#section-4.3 (case we want to auth a microservice for example)

I could keep linking all the docs, but I think this isn't necessary as someone made a great OAuth server implementation here: https://github.com/go-oauth2/oauth2

My point is: could we create an oauth strategy based on the OAuth server implementation that go-oauth2 made?

shaj13 commented 2 years ago

@IzioDev FYI, go-guardian support oauth2 but first, let me explain,

oauth2 depends on three factors

OAuth 2.0 protocol flow requires the client to redirect the end-user to the authorization server and once the authorization is granted the end-user is redirected back to the client with the authorization response from there the client starts sending the granted access token to the resource server, when a request is sent to the resource server, it extracts the access token and verifies it against the authorization server, the resource server may cache invocation results to reduce latency and for performance purposes. however, when the token expired both the resource server and authorization server rejects the request, the client handles this rejection by sending the refresh token to the authorization server indeed to obtain a new access token to continue the flow.

anyway, according to oauth.net and rfc, OAuth 2.0 focuses on client developer simplicity while providing specific authorization flows for web applications, desktop applications, mobile phones, and living room devices. Most of the applications today are split into tine services (microservices) to be operated at any scale, etc... so, the client decoupled from the resource server.

unfortunately, GoGuardian can't handle redirect requests, and since its aim is to be working in resource servers we have only implemented the last step in OAuth 2.0 protocol flow. the same mechanism also has been adopted in Kubernetes authentication system.

don't forget the client should save refresh tokens in a secure manner, so it will be easier to store this kind of data on the client-side (phone DB, web browser, etc) instead of saving it into a server-side DB which requires extra tracking of tokens like encryption/decryption, wiping inactive tokens, etc... .

however, you can compose golang/oauth2 to obtain/refresh tokens, and GoGuardian for verification.

IzioDev commented 2 years ago

Thank you very much for this clarification. I was getting this wrong obviously.

Just to make sure I well understand :

  1. Go Guardian is able to verify an access token.
  2. It's up to the end-user (a developer using Go Guardian) to provide the resource server (Keycloak, OAuth, FusionAuth, etc...) and hence the /access-token and /refresh-token routes.

I really appreciate the time you spend on making this clarification.

PS: I think we can close the issue since it was not an issue, but something I got wrongly.

c-nv-s commented 2 years ago

it might help to have an oauth2 strategy example in the example folders? I believe there are some free oauth2 testing servers available online you could use to demonstrate. e.g. https://www.oauth.com/playground/

shaj13 commented 2 years ago

@c-nv-s agree, this the primary reason kept this issue open,

However, I'd like to know what examples you expect to see

c-nv-s commented 2 years ago

I think composed client and resource server auth would cover more ground

shaj13 commented 2 years ago

@c-nv-s please take a look #119 before merging it to the main branch. it would be nice if you can test it :). looking forward to your feedback

c-nv-s commented 2 years ago

looking into it now.

c-nv-s commented 2 years ago

the code looks good, I'm still trying to test with a separate oidc provider (Authelia) to see if it works. Maybe you might want to substitute: Endpoint: google.Endpoint,

for

Endpoint:    oauth2.Endpoint{
    AuthURL:  "https://accounts.google.com/o/oauth2/auth",
    TokenURL: "https://oauth2.googleapis.com/token",
        AuthStyle:   0,
},

just so it is clear how a user could customize it for their own provider ? but you could leave a comment showing that golang.org/x/oauth2/<provider_name> packages are available so you don't have to manually search for the endpoint details?

Also it might be nice to include a small comment showing how someone could have accessed info from an additionally requested scope e.g. email, profile

c-nv-s commented 2 years ago

I can confirm it works with Authelia with the above change