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

Setting JWT Refresh Token from login endpoints #398

Closed
rikoz opened this issue Jun 30, 2019 · 49 comments · Fixed by #361
Closed

Setting JWT Refresh Token from login endpoints #398

rikoz opened this issue Jun 30, 2019 · 49 comments · Fixed by #361

Comments

@rikoz
Copy link

rikoz commented Jun 30, 2019

What problem does this feature solve?

Hello, I have a feature request and i need help from anyone who can help

What I have::
please i'm making use of JWT setting the access token in the property name... the problem is access token expires after some minutes and becomes invalid throwing a 401 (Unauthorized) error and this will make the application to logout.

What I want to acheive::
A way to set the refresh token so when access token expires and throws such error, I should intercept to use refresh token to fetch a new access token and then repeat request.

I'm using DRF for backend.
I really need your help as this app deploys in few days and i need to fix it up

Thanks
Screenshot from 2019-06-30 03-57-19.png

Screenshot from 2019-06-30 03-56-28.png

Screenshot from 2019-06-30 04-01-42.png

What does the proposed changes look like?

Please add another optional field to login endpoint that sets refresh token.... I already see the auth module has the function to set it. An axios interceptor will take care of the rest feature of having to fetch a new access token once expired using the refresh token in payload.
Also a new endpoint to specify what url is called using this refresh token to fetch access

Screenshot from 2019-06-30 04-07-39.png

To look something like this
Screenshot from 2019-06-30 04-12-15.png

and then a $auth.tokenRefresh function.

Thanks

This feature request is available on Nuxt community (#c366)
@ghost ghost added the cmty:feature-request label Jun 30, 2019
@geoffreylzf
Copy link

I also waiting this features to be merged, for short term solution, I set the jwt token expire time to 8 hour

@JoaoPedroAS51
Copy link
Collaborator

Hi @rikoz, we are working on refresh support. Check this out #361

We haven't finished yet, but at the meantime you can use the new branch (feat/refresh).

You can find the docs in the PR.

@rikoz
Copy link
Author

rikoz commented Jul 14, 2019

Okay, I will check it out now.

Let me know when it's updated into the main branch so i can update my node package. I will be waiting

Can you give me a direct link to docs

thanks I appreciate.

@JoaoPedroAS51
Copy link
Collaborator

JoaoPedroAS51 commented Jul 14, 2019

@rikoz I'll let you know when we merge it.

Docs can be found here #361

@rikoz
Copy link
Author

rikoz commented Jul 15, 2019

Okay thanks, seen

@mckraemer
Copy link

Any updates?

@vonlooten
Copy link

@rikoz I'll let you know when we merge it.

Docs can be found here #361

Hey Joao, do you have any news?
I think this is a feature many people need :)

Is there a way I can help?

@JoaoPedroAS51
Copy link
Collaborator

Hey Joao, do you have any news?
I think this is a feature many people need :)

Is there a way I can help?

Hi @danielmoeck, I'm sorry, I don't have any news about it. I had to stop working a few months ago due to personal problems.

But yeah I agree, many people need this feature! Actually, I use this branch in my project in production! For me it works fine and stable.

I guess is up to @pi0 to make the final reviews and merge it.

@JoaoPedroAS51
Copy link
Collaborator

@danielmoeck @mckraemer
I just released a new update, the branch feat/refresh is up-to-date now ;)

@vonlooten
Copy link

vonlooten commented Feb 23, 2020

@danielmoeck @mckraemer
I just released a new update, the branch feat/refresh is up-to-date now ;)

Thank you! I will try the branch you mentioned :)

@vonlooten
Copy link

oh damn @JoaoPedroAS51
When I call the /users/me route the auth-module will send Authorization: JWT undefined.
It worked with master. Do you have a hint? :)

@JoaoPedroAS51
Copy link
Collaborator

Hey @danielmoeck! Let's find out together!
Can you show me your auth config in nuxt.config.js and send me a screenshot of the error?

@vonlooten
Copy link

vonlooten commented Feb 25, 2020

Yes that sounds great @JoaoPedroAS51
I expected the basic login to work in the way it did before just with the refresh token.
Or did I understand this wrong?

The errorcode is basically 401
The header to the /users/me route sends

Authorization: JWT undefined

At the moment I'm using this version of the auth-module
"@nuxtjs/auth": "github:nuxt-community/auth-module#feat/refresh",


auth: {
    localStorage: false,
    strategies: {
      local: {
        endpoints: {
          login: { url: '/api/v1/auth/jwt/create/', method: 'post', propertyName: 'access' },
          user: { url: '/api/v1/auth/users/me/', method: 'get', propertyName: false },
          logout: false
        },
        tokenRequired: true,
        tokenType: 'JWT'
      }

    }
  },

@JoaoPedroAS51
Copy link
Collaborator

Hi @danielmoeck, I guess the problem is in your config. We refactored the config in the feat/refresh branch. You can check the docs here #361 (comment)

Try changing to this and tell me what happens:

auth: {
    localStorage: false,
    strategies: {
      local: {
        _scheme: 'refresh',
        token: {
          property: 'access'
        },
        refreshToken: {
          property: 'refresh_token' // change to your refresh token property
        },
        user: false,
        endpoints: {
          login: { url: '/api/v1/auth/jwt/create/', method: 'post' },
          refresh: { url: '/api/v1/auth/jwt/refresh/', method: 'post' }, // change to your refresh token url
          user: { url: '/api/v1/auth/users/me/', method: 'get' },
          logout: false
        },
        tokenRequired: true,
        tokenType: 'JWT'
      }
    }
  }

@vonlooten
Copy link

Wow thank you so much for your fast reply, thats really cool!

I think everything works, I get my access and refresh token 👍 yeah!

I'm just wondering why my auth/users/me call returns "Authentication credentials were not provided.". Do you know where I could've made a mistake?

@JoaoPedroAS51
Copy link
Collaborator

JoaoPedroAS51 commented Feb 25, 2020

@danielmoeck I'm happy to know it worked! :)

About "Authentication credentials were not provided", try to use tokenType: 'Bearer'

@vonlooten
Copy link

@JoaoPedroAS51 I am very happy that you helped me! Awesome! 💯
(it works)

Thank you so much!

@JoaoPedroAS51
Copy link
Collaborator

@danielmoeck Yay! And if you face any other problem, don't hesitate to contact me! I'll be happy to help! ;)

@pi0 pi0 mentioned this issue Mar 3, 2020
4 tasks
@pi0 pi0 closed this as completed in #361 Mar 15, 2020
@Dav3rs
Copy link

Dav3rs commented Jul 23, 2020

Hi, Help Please!! How can i set the refresh token manually????? Just as I set the token with "setUserToken (token)", I want to set the refreshToken in that way, maybe with a setRefreshToken() function. There is already a way to do that?

@JoaoPedroAS51
Copy link
Collaborator

Hi @Dav3rs! Just pass the refresh token as second parameter setUsetToken(token, refreshToken) :)
I presume you are using the dev version (@nuxtjs/auth-next), as refresh support wasn't released yet.

@Dav3rs
Copy link

Dav3rs commented Jul 23, 2020

Thanks @JoaoPedroAS51 !!! Maybe that parameter could be updated in the docs in
https://dev.auth.nuxtjs.org/api/auth.html#setusertoken-token

@JoaoPedroAS51
Copy link
Collaborator

@Dav3rs Yes, you're right. I'll update it.

@stephenjason89
Copy link

stephenjason89 commented Oct 7, 2020

@JoaoPedroAS51 I tried but checking cookie, refreshtoken is false.
Is this working on 4.9.1?

auth: {
    localStorage: false,
    strategies: {
      local: {
        _scheme: 'refresh',
        token: {
          property: 'access'
        },
        refreshToken: {
          property: 'refresh_token' // change to your refresh token property
        },
        user: false,
        endpoints: {
          login: { url: '/api/v1/auth/jwt/create/', method: 'post' },
          refresh: { url: '/api/v1/auth/jwt/refresh/', method: 'post' }, // change to your refresh token url
          user: { url: '/api/v1/auth/users/me/', method: 'get' },
          logout: false
        },
        tokenRequired: true,
        tokenType: 'JWT'
      }
    }
  }

EDIT: tried it with "@nuxtjs/auth-next" instead and it is working. "@nuxtjs/auth-next" and "@nuxtjs/auth" got me confused. Thank you :)

@JoaoPedroAS51
Copy link
Collaborator

Hi @stephenjason89! I'm happy to know it worked! :)

You should make some refactors to ensure that your config works in @nuxtjs/auth-next.

auth: {
    localStorage: false,
    strategies: {
      local: {
        scheme: 'refresh', // `_scheme` is now `scheme` 
        token: {
          property: 'access',
          type: 'Bearer', // `tokenType` is now `token.type`
          required: true // `tokenRequired` is now `token.required`
        },
        refreshToken: {
          property: 'refresh_token' // change to your refresh token property
        },
        user: {
          property: false,  // `user` property is now `user.property`
          autoFetch: true
        },
        endpoints: {
          login: { url: '/api/v1/auth/jwt/create/', method: 'post' },
          refresh: { url: '/api/v1/auth/jwt/refresh/', method: 'post' },  // change to your refresh token url
          user: { url: '/api/v1/auth/users/me/', method: 'get' },
          logout: false
        }
      }
    }
  }

@stephenjason89
Copy link

stephenjason89 commented Oct 7, 2020

@JoaoPedroAS51 Thank you for replying to me.
However, I am using laravel passport and issue arises whenever it tries to refresh the token
I get Unauthenticated error message from laravel passport.
I believe i should follow this format

        'grant_type' => 'refresh_token',
        'refresh_token' => 'the-refresh-token',
        'client_id' => 'client-id',
        'client_secret' => 'client-secret',
        'scope' => '',

But currently it is just passing refresh_token
How can i add this?

Currently my config is this

auth: {
        redirect: {
            login: '/login',
            logout: '/',
            callback: '/login',
            home: '/',
        },

        localStorage: false,
        strategies: {
            local: {
                scheme: 'refresh',
                token: {
                    property: 'access_token',
                    maxAge: 60, // Just set this at 1 minute to try the auto refresh
                    type: 'Bearer',
                },
                refreshToken: {
                    property: 'refresh_token',
                    maxAge: 60 * 60 * 24 * 30, // same as refresh_ttl but in seconds
                },
                user: {
                    property: '',
                    autoFetch: true,
                },
                endpoints: {
                    login: { url: '/oauth/token', method: 'post' },
                    refresh: {
                        url: '/oauth/token/refresh',
                        method: 'post',
                        headers: {
                            'X-Requested-With': 'XMLHttpRequest',
                            'Content-Type': 'application/json',
                        },
                        data: { //Failed attempt to add the additional params here
                            grant_type: 'refresh_token',
                            client_id: '2',
                            client_secret: 'EKZWv2BF9A3I2VXZZ1x0LMu50nHxkcseCvk7BT8U',
                            scope: '',
                        },
                    },
                    user: { url: '/api/user', method: 'get' },
                    logout: { url: '/api/logout', method: 'post' },
                },
            },
        },
    },

Thank you so much

image

image

@JoaoPedroAS51
Copy link
Collaborator

@stephenjason89 Laravel Passport it's pretty easy to configure. Just use laravel/passport provider :)
Documentation: https://dev.auth.nuxtjs.org/providers/laravel-passport

@stephenjason89
Copy link

stephenjason89 commented Oct 7, 2020

@JoaoPedroAS51 How can i use the laravel/passport provider with a username and password?
I believe the docs uses client ID and client secret alone to get a token?
Or maybe i might be doing this the wrong way?

What I am trying to achieve is for users to be able to login using username and password which will be passed to my backend (passport) that will issue a token and a refresh token.

Thank you

@JoaoPedroAS51
Copy link
Collaborator

JoaoPedroAS51 commented Oct 7, 2020

@stephenjason89 It works with password grant, just need to set grantType to password

nuxt.config

auth: {
  laravelPassport: {
    name: 'laravelPassportPassword',
    provider: 'laravel/passport',
    endpoints: {
      user: {
        url: '/api/auth/user'
      }
    },
    token: {
      maxAge: 1800
    },
    refreshToken: {
      maxAge: 60 * 60 * 24 * 30
    },
    clientId: 'client-id',
    clientSecret: 'client-secret',
    grantType: 'password'
  }
}

Then to login:

this.$auth.loginWith('laravelPassport', {
  data: {
    username: 'test@test.com',
    password: '12345678'
  }
})

You can check the demo from the repo: https://github.com/nuxt-community/auth-module/tree/dev/demo

Laravel Passport documentation for Password Grant flow: https://laravel.com/docs/8.x/passport#password-grant-tokens

@stephenjason89
Copy link

@JoaoPedroAS51 You are awesome. I am trying it now. Sorry I was editing my previous question when you replied.

The same challenge is what i am facing with social login.
I have laravel socialite and the current implementation on the docs for facebook is

auth: {
  strategies: {
    facebook: {
      endpoints: {
        userInfo: 'https://graph.facebook.com/v2.12/me?fields=about,name,picture{url},email,birthday'
      },
      clientId: '...',
      scope: ['public_profile', 'email', 'user_birthday']
    },
  }
}

This works only half way. I will have a token from facebook but I won't be able to verify on my server if this is already registered and if it is, issue a token from passport.

Thank you :)

@stephenjason89
Copy link

stephenjason89 commented Oct 7, 2020

I might be missing something, i copied the config on the repo you linked me.

here's my nuxt

    axios: {
        proxy: true,
    },
    proxy: {
        '/api': 'http://localhost',     //localhost is my laravel and localhost:3000 is my nuxt
        '/laravel': {
            target: 'http://localhost',
            pathRewrite: { '^/laravel': '/' },
        },
    },
   auth: {
        cookie: {
            secure: false,
        },
        localStorage: false,

        strategies: {
            laravelPassportPasswordGrant: {
                name: 'laravelPassportPassword',
                provider: 'laravel/passport',
                url: '/laravel',
                endpoints: {
                    user: {
                        url: '/api/auth/user',
                    },
                },
                token: {
                    maxAge: 1800,
                },
                refreshToken: {
                    maxAge: 60 * 60 * 24 * 30,
                },
                clientId: '2',
                clientSecret: 'EKZWv2BF9A3I2VXZZ1x0LMu50nHxkcseCvk7BT8U',
                grantType: 'password',
            },
        },
    },

Then i called it like this

        async passwordGrantLogin() {
            await this.$auth.loginWith('laravelPassportPasswordGrant', {
                data: {
                    username: this.user.username,
                    password: this.user.password,
                },
            })
        },

Everytime i try to login, the only thing i see in my network tab is index.js

EDIT: i actually went ahead and copied the whole Auth block and used

laravelPassportPasswordGrant: {
                name: 'laravelPassportPassword',
                provider: 'laravel/passport',
                url: '/laravel',
                endpoints: {
                    user: {
                        url: '/api/auth/user',
                    },
                },
                token: {
                    maxAge: 1800,
                },
                refreshToken: {
                    maxAge: 60 * 60 * 24 * 30,
                },
                clientId: '2',
                clientSecret: 'EKZWv2BF9A3I2VXZZ1x0LMu50nHxkcseCvk7BT8U',
                grantType: 'password',
            },

But there were no errors nor were there network traffic to my laravel endpoint. I only see index.js and my default error handler.

@JoaoPedroAS51
Copy link
Collaborator

@stephenjason89 I think your laravel target should be http://localhost:8000

Sorry for the delay. I'm not used to laravel socialite. I'm doing some research.

@stephenjason89
Copy link

@JoaoPedroAS51 I changed mine to port 80

@JoaoPedroAS51
Copy link
Collaborator

ok

@stephenjason89
Copy link

Thank you for helping me, I will try to do something about the laravel socialite and will report back once i figure it out.

@JoaoPedroAS51
Copy link
Collaborator

JoaoPedroAS51 commented Oct 7, 2020

@stephenjason89 About the facebook I think you should set the userInfo to your laravel app like http://localhost/api/auth/facebook/user then in your controller add something like this:

public function user ()
{
    $user = Socialite::driver('facebook')->userFromToken(request()->bearerToken());

    return response()->json($user)
}

@stephenjason89
Copy link

stephenjason89 commented Oct 7, 2020

@JoaoPedroAS51 I will try that now.
Btw, I am still having troubles with passportpasswordgrant and i copied everything from the repo :(

@JoaoPedroAS51
Copy link
Collaborator

For facebook:

auth: {
  strategies: {
    facebook: {
      endpoints: {
        userInfo: 'http://localhost/api/auth/facebook/user'
      },
      clientId: '...'
    },
  }
}

Btw, I am still having troubles with passportpasswordgrant and i copied everything from the repo :(

Ok, I'll see if I find where is the error.

@stephenjason89
Copy link

@JoaoPedroAS51 Thank you so much. You reply so fast. I'm so grateful for your help.

@JoaoPedroAS51
Copy link
Collaborator

I'm happy to help! :)

@JoaoPedroAS51
Copy link
Collaborator

@stephenjason89 Can you add me on discord? Joao Pedro AS51#1284

@stephenjason89
Copy link

I will add you now :)

@stephenjason89
Copy link

Thank you so much for helping me @JoaoPedroAS51 I really appreciate it.

@sunnykan314
Copy link

I have similar issue to one above and its solution doesn't work for my case... (Authorization: JWT undefined)
Client send login request and get response like below
2021-02-21_6-10-55
2021-02-21_6-09-56
But if I try this.$auth.loggedIn , it gives false
and /user request doesn't contain Authorization header
2021-02-21_6-11-34
2021-02-21_6-12-18
this is my auth setting
2021-02-21_6-17-24
Please help me....

@osahene
Copy link

osahene commented Jul 8, 2021

Good day @JoaoPedroAS51
I am having challenges implementing this code. I am using django 3.2.3, django rest_framework and simple_jwt.

`auth: {
localStorage: false,
cookie: {
options:
{ sameSite: 'Lax' }
},
strategies: {
local: {
scheme: 'refresh',
token: {
property: 'access',
maxAge: 1800,
global: true,
type: 'Bearer'
},
refreshToken: {
property: 'refresh_token',
data: 'refresh_token',
maxAge: 60 * 60 * 24 * 30
},
user: {
// property: 'user',
autoFetch: false
},
endpoints: {
login: {url: "/account/login/", method: "post", },
refresh: { url: "/account/api-token/", method: 'post' },
logout: false,
user: { url: "/account/current-user/", method: "get", },
},

  },
},

},`

I get the error message XHRGEThttp://127.0.0.1:8000/account/current-user/
[HTTP/1.1 401 Unauthorized 5ms]

detail "Given token not valid for any token type"
code "token_not_valid"
messages [ {…} ]
0 Object { token_class: "AccessToken", token_type: "access", message: "Token is invalid or expired" }
token_class "AccessToken"
token_type "access"
message "Token is invalid or expired"

I would be grateful for your assistance. Thank you

Copy link
Collaborator

Hi @osahene! Let's see if we can make this work! :)
Can you show me your login response? Also, are you using auth v4 or v5?

@osahene
Copy link

osahene commented Jul 18, 2021

Hi @JoaoPedroAS51,
I am currently using auth v5. and this is my auth section in the nuxt.config.js
` auth: {
localStorage: {
prefix: "auth."
},
cookie: {
prefix: "auth.",
options:
{ sameSite: 'Lax',
expires: 7,
}
},
redirect: {

    login: false,
    logout: false,
    callback: false,
    home: false,
  },
strategies: {            
  local: {       
    scheme: 'refresh',
    token: {
      property: 'access',
      prefix: '_token.',
      global: true,
      name: 'Authorization',
      type: 'Bearer'
    },
    refreshToken: {
      property: 'refresh',
      data: 'refresh',
      maxAge: 60 * 60 * 24 * 30
    },
    user: {
      property: false,
     autoFetch: true
    },
    endpoints: {
      login: { url: 'account/login/', method: 'post' },
      refresh: { url: 'account/token/refresh', method: 'post' },
      user: { url: 'account/current-user/', method: 'get',  },
      logout: false
      // { url: 'account/logout/', method: 'post' }
    },
   
},                                                              
// plugins: ['~/plugins/auth.js']

},and the store export const getters = {
isAuthenticated(state) {
return state.auth.loggedIn
},
loggedInUser(state) {
return state.auth.user
},
};`

When I console log the response I get
Object { data: {…}, status: 200, statusText: "OK", headers: {…}, config: {…}, request: XMLHttpRequest } ​ config: Object { url: "account/login/", method: "post", data: "{\"email\":\"david@gmail.com\",\"password\":\"alaba\"}", … } ​​ adapter: function xhrAdapter(config) ​​ baseURL: "http://127.0.0.1:8000/" ​​ data: "{\"email\":\"david@gmail.com\",\"password\":\"alaba\"}" ​​ headers: Object { Accept: "application/json, text/plain, */*", "Content-Type": "application/json;charset=utf-8" } ​​ maxBodyLength: -1 ​​ maxContentLength: -1 ​​ method: "post" ​​ onDownloadProgress: function onProgress(e) ​​ onUploadProgress: function onProgress(e) ​​ timeout: 0 ​​ transformRequest: Array [ transformRequest(data, headers) ] ​​ transformResponse: Array [ transformResponse(data) ] ​​ url: "account/login/" ​​ validateStatus: function validateStatus(status) ​​ xsrfCookieName: "XSRF-TOKEN" ​​ xsrfHeaderName: "X-XSRF-TOKEN" ​​ <prototype>: Object { … } ​ data: Object { email: "david@gmail.com", tokens: {…} } ​ headers: Object { "content-length": "487", "content-type": "application/json" } ​ request: XMLHttpRequest { readyState: 4, timeout: 0, withCredentials: false, … } ​ status: 200 ​ statusText: "OK" ​ <prototype>: Object { … } login.vue:146

The loggedInUser, isAuthenticated as well as the auth. user returns false.
The local storage in the browser indicates that the auth._local_refreshtoken.local has a value false.

thank you

@osahene
Copy link

osahene commented Jul 21, 2021

I had a solution to the issue through Dev Internals https://www.youtube.com/watch?v=Tqm9hVCSQDI&list=PL0xSLrZOcI4sbSEO9c5NnlPYWAvJzl05I&index=11

@iamr0man
Copy link

iamr0man commented Oct 4, 2021

hi, @JoaoPedroAS51, i have issue with refresh token endpoint, can you help me please?
I need to pass refreshToken property in header Authorization, but not in body of request. How I can do it ?
I'm using auth 5v and this is my auth config:

auth: {
    strategies: {
      local: {
        scheme: 'refresh',
        token: {
          property: 'accessToken',
          maxAge: 86400,
          global: true,
          type: 'Bearer'
        },
        refreshToken: {
          prefix: 'refreshToken',
          property: 'refreshToken',
          data: 'refreshToken',
          maxAge: 60 * 60 * 24 * 30
        },
        user: {
          property: ''
          // autoFetch: true
        },
        endpoints: {
          login: { url: '/api/auth/login', method: 'post', propertyName: 'accessToken' },
          refresh: {
            url: '/api/auth/refreshtoken',
            method: 'post',
          },
          user: { url: '/api/user-profile/data', method: 'get', propertyName: '' },
          logout: { url: '/api/auth/logout', method: 'post' }
        }
      }
    }
  }

135848519-14b2d303-afec-4082-8f52-9f699d473058
135848627-2b82f70c-59b4-4fa3-848d-50dd6aeb881b

@etdevs1
Copy link

etdevs1 commented Oct 10, 2022

@iamr0man I have the same issue. How did you solve your problem?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.