Trying to implement OpenId Connect in Web Application consisting of following components
Identity Provider and Resource Server are the same application.
SPA use Password Flow to get access_token
and stores into the cookie. Storing access_token
into cookie has it's security threads, but's it's a different story.
Problem
access_token
issued by IdP is expired after 30 min and SPA needs to renew token without asking users for credentials again.
Solution
IdP returns refresh_token
along with access_token
. Whenever SPA gets 401
from Resource Server, it sends refresh_token
to IdP and get's new access_token
back.
Problem
Sending refresh_token
to SPA is bad practice.
A Single Page Application (normally implementing Implicit Grant) should not under any circumstances get a Refresh Token. The reason for that is the sensitivity of this piece of information. You can think of it as user credentials since a Refresh Token allows a user to remain authenticated essentially forever. Therefore you cannot have this information in a browser, it must be stored securely.
Suggested solution
When the Access Token has expired, silent authentication can be used to retrieve a new one without user interaction, assuming the user's SSO session has not expired.
I think Silent Authentication is not applicable to Password Flow when IdP and Resource Server is same application. access_token
issued by IdP is only piece of information which can be used to authorize against Resource Server/IdP after its expiration, how a client can convince IdP to issue new access_token
? (without sending refresh_token
)
Found angular-oauth2-oidc library which uses refresh_token
to renew access_token
.
What is best practice/solution in this case to renew access_token
?
technical details
To refresh your access token as well as an ID token, you send a token request with a grant_type of refresh_token . Be sure to include the openid scope when you want to refresh the ID token. If the refresh token is valid, then you get back a new access and the refresh token.
You Can Store Refresh Token In Local Storage Storing tokens in browser local storage provides persistence across page refreshes and browser tabs; however, if malicious users managed to run JavaScript in the SPA using a cross-site scripting (XSS) attack, they could retrieve the tokens stored in local storage.
Web applications To refresh the token, your API needs a new endpoint that receives a valid, not expired JWT and returns the same signed JWT with the new expiration field. Then the web application will store the token somewhere.
When an access token expires, a refresh token is used to get a new access token and it also returns a new refresh token. Now if this new access token expires & a new/updated refresh token is used to get the next access token, it will also receive a newer refresh token.
Single page applications must not receive refresh tokens. That has been established rules in OAuth 2.0 and OpenID Connect.
One good option I see here is to use Implicit Flow. This will establish a front channel session from your browser to Identity Provider. With password grant type you do a back-channel call (POST), so you don't get such session.
Usually this is a cookie which points to information about previous logged in status (these are identity provider specifics). With completion of the flow, SPA will receive the access token
. As you figured out, it will expire. But once that happens, SPA can trigger another implicit flow, but this time with prompt
query parameter.
prompt
Space delimited, case sensitive list of ASCII string values that specifies whether the Authorization Server prompts the End-User for reauthentication and consent. The defined values are: none , login, consent and select_account
If you identity provider maintain a long lived session (ex:- few hours or days) or if it maintain a remember me cookie, SPA could use prompt=none
making it to skip login step from identity provider. Basically, you are getting browser based SSO behaviour with this.
Using the Resource Owner Password Credentials flow defeats the refresh token storage argument: instead of not being able to store the refresh token in a secure place, the SPA would now have to store the Resource Owner credentials in a secure place (assuming you want to avoid requesting username/password from the user frequently). The Implicit grant was designed for usage with an SPA, so it is better to stick with that.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With