How to invalidate or revoke jwt access token using Identity server 4 JWT authentication and Resource Owner Password grant? - asp.net-core

We have used JWT authentication scheme and resource owner password grant type with identity server. Backend is .Net core based micro services which is providing access token to angular based front end website.
As jwt token is not revocable and business requirement is to have longer access token lifetime, it seems only option is to have track of blacklisted tokens in database or cache.
Is there any way to modify the access token on backend and make it expire immediately when user triggers log out from frontend?

JWT cannot be revoked, it is by design as it is self-contained. Revocable alternative is Reference token which is not self-contained and thus server needs to actively communicate with identity server.
The compromise and common approach is to set access token lifetime to lower value and increase refresh token lifetime. Refresh tokens are revocable - it is supported by identity server 4 as well. So it is all about trade-off between the frequency of communication with your Identity server and long access token lifetime.

The JWT tokens are stored in the browser, so you can delete the cookie of it.
But this option gives no security on the server side.
If you are worried about deleted/suspended accounts then yes, you have either to create a blacklist but you have to compare them for each request.
The other option is to reduce the expire times and rotate them. there is a post with more details here Invalidating JSON Web Tokens

Related

Where to store tokens obtained through OAuth2 (OpenID Connect)

I build an application that uses some Identity Provider (Auth0, FusionAuth, Azure AD, AWS Cognito) on user's choice.
I'm using Authorization Code flow.
And i faced issue with storing tokens.
I want to use Identity Provider to only user's sign in, i do not need to store who is the user (name, email etc.). I just need to authenticate user and be sure that user come from Identity Provider that i can trust.
So i have 4 questions:
Do i need to store tokens if i am not consider to use them to make requests to the Identity Provider.
If no goto 4 question. If yes i want to know what the best way to store them (save in session with db or just send them as accessToken for Header and refreshToken in cookie)
How i can validate access token, because as i know access token may or may not be JWT. Make request to IP on each request is not the best way, because of amount of requests.
Should i use my own created pair of access and refresh tokens to validate requests from Front End.
I'm only recently started investigate OAuth2 and will appreciate any answers.
As of now i have this flow:
From Front End(FE) user redirects to the Identity Provider(IP) to sign in.
IP redirects to the Back End(BE) with code.
BE make request to IP to obtain tokens.
BE validates that authorization is valid (via nonce and state).
BE redirects user to the FE with refreshToken in the httpOnly secure cookie and accessToken in query to store it in localStorage.
When FE make request to BE i validate accessToken(JWT) using jwks.
In OAuth you should not generally have to implement plumbing to build your own token stores. Eg tokens can be stored in strongly encrypted HTTP only SameSite=strict cookies. However you have to stay within cookie size limits. The best way to do this is to issue opaque tokens (such as UUIDs) to internet clients. The Phantom Token Pattern has more info on this.
You should not use foreign access tokens in your own APIs. As you are discovering, you may not be able to validate them. Also they will not have meaningful scopes and claims and you will not be able to authorize API requests properly. Instead issue your own tokens for your own APIs.
AUTHORIZATION SERVER
It is possible to issue your own tokens in code but this is not recommended. Instead, the preferred option is to use an Authorization Server. One option is the free community edition of the Curity Identity Server.
This component will take care of connections to Identity Providers for you. It will then issue tokens for you, so that your apps and APIs only ever deal with tokens from a single provider.

How to overcome from a security breach in Jwt tocken validation

I have used jwt token securing angular application and in the backend, we have used asp.net core API. After login successfully we have saved the token in local storage in web browser memory and we log out from the application simply remove the token from browser memory.
We can stop the user to access the application through the application but if some have the token he can access the endpoint using postman and other api test tool. How can we overcome this problem.Is there any way to remove the token or expire the token manually.
Revoke the jwt token is not easy , there is no standard way to revoke access tokens unless the Authorization Server implements custom logic which forces you to store generated access token in database and do database checks with each request.
A simply way is using short lived access tokens and refresh token , use refresh token to renew the access token , if you want to revoke the user , revoke the refresh token on server side , clear refresh token and access token on client side .
Another way is reference tokens. The basic idea is Authorization Server will store the contents of the token in a data store and will only issue a unique identifier for this token back to the client. The API receiving this reference must then open a back-channel communication to Authorization Server to validate the token , so that the server side could control whether reference token(unique identifier) is still available . Identity server 4 also provides the reference token feature :
http://docs.identityserver.io/en/latest/topics/reference_tokens.html

Asp.net Core with Identity server 4

I have 2 website that are using identity server Authentication (which is a third website)
if i log out from the identity server website (i am using quick start) how can i force the 2 other website to validate if the user is still log in, and this on every round trip to the server (post back).
For browser based apps you can call the session endpoint:
All applications that the user has logged into via the browser during
the user’s session can participate in the sign-out.
This will however not invalidate JWT tokens as these are self-contained and remain valid until expiration.
The only way to logout a JWT 'almost realtime', is to set the expiration to a minimum and use refresh tokens to renew the access token.
These refresh tokens can be revoked using the revocation endpoint:
This endpoint allows revoking access tokens (reference tokens only)
and refresh token.
This way you don't need a roundtrip on each call. An alternative that does is to use reference tokens:
When using reference tokens - IdentityServer will store the contents
of the token in a data store and will only issue a unique identifier
for this token back to the client. The API receiving this reference
must then open a back-channel communication to IdentityServer to
validate the token.
Using the revocation endpoint you can revoke the reference tokens at any time you like.

OpenId Connect renew access_token in SPA

Trying to implement OpenId Connect in Web Application consisting of following components
Identity Provider
Resource server
Single Page Application acting as Client.
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
Identity Provider - ASP.NET Core + Openiddict library.
SPA - AngularJs application.
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.
Further to previous answers, the latest OAuth working group guidance for SPAs no longer recommends use of the implicit flow.
If you have simple, shared domain app (IdP, RS and client on a single domain) then you should consider not using OAuth at all. From the doc:
OAuth and OpenID Connect provide very little benefit in this
deployment scenario, so it is recommended to reconsider whether you
need OAuth or OpenID Connect at all in this case. Session
authentication has the benefit of having fewer moving parts and fewer
attack vectors. OAuth and OpenID Connect were created primarily for
third-party or federated access to APIs, so may not be the best
solution in a same-domain scenario.
If you are using OIDC/OAuth in a SPA, they recommend the auth code flow with PKCE.

What type of token/auth to use for non-interactive API clients in an OIDC context?

We consider using OpenID Connect with ID tokens for authentication of our public API.
These are the usage scenarios we'd like to cover:
Web UI (single page, client-side JavaScript app)
Command line interface (CLI) used in an interactive session
CLI used non-interactively, e. g. in a CI/CD pipeline
Other API calls executed in a non-interactive session
The idea for (1) and (2) is to use the OIDC implicit grant type, so that the user authenticates interactively (username/password) at our OpenID Connect identity provider and permits the RP (relying party, client) to access the users identity. The identity provider will then issue a short-lived ID token, a refresh token and (optionally?) an access token to the RP.
For (3) and (4) an interactive authentication is out of the question. We'd instead like to issue tokens to the users which allow them to access our API on their behalf. These tokens should be long living, only invalidated when they get deleted in the system.
Still, we want to use JWT just like the ID tokens issued by the identity provider as a carrier of identity information for all API requests internally.
My questions are:
Can this be done purely with one of the tokens issued by the OpenID Connect implicit grant type?
Can an access token be issued in a long-lived (no expiry, only invalidated by deleting from the system) way and then be exchanged by the client against an ID token?
Or is the refresh token the thing to use for exactly that?
Or do we have to solve this outside OpenID Connect? Which leaves the question how to resolve opaque tokens from API requests against identity details (JWT) for use in our API/services?
If you use implicit flow (for Scenarios 1 and 2), you can't use refresh tokens. You need client credentials (client ID and secret) to request for refresh tokens. In the Implicit flow, we don't store any client credentials.
When a client is Public client (SPA,etc..), it is not safe to store client secret in it. So public clients generally use Implicit flow. Implicit flow doesn't support refresh tokens. Some of the OIDC libraries implement Silent token renewal/refresh feature to circumvent the absence of refresh tokens. But there are some limitations with that model (you need to have active session with IDP to get the renewal working without any interruption)
TL;DR -> If a client is public client, use implicit flow (which don't need client secret to get access tokens from IDP). Implicit flow doesn't support refresh tokens.
Can this be done purely with one of the tokens issued by the OpenID Connect implicit grant type?
It is not possible to use refresh tokens with implicit flow. Authorization code flow supports refresh tokens but can't be used with SPA clients. So you need a combination of OAuth 2.0/OIDC flows.
Can an access token be issued in a long-lived (no expiry, only invalidated by deleting from the system) way and then be exchanged by the client against an ID token?
These are two different things:
"Invalidated by deleting from the system" : With this we are discussing about Self-Contained tokens vs Reference tokens.
Self-Contained Tokens: These tokens contains all the information required to validate its authenticity in it - for e.g. the issuer details, its validity, etc.. A client don't need to make a back-channel call to STS to confirm the authenticity. These tokens are sometimes hard to revoke and will be valid for the duration as specified in the token.
Reference Tokens: Reference tokens are generally opaque tokens which contains a GUID like identifier in it and no other details. In order to validate the authenticity of these tokens, the client needs to make a back-channel call to STS. One main advantage is it can be easily revoked by deleting the corresponding identifier in STS DB.
"exchanged by the client against an ID token Refresh token" - I am assuming you are referring to Refresh tokens instead of ID token. We use Refresh token for this purpose
Or is the refresh token the thing to use for exactly that?
Yes. Refer to the above comments
Or do we have to solve this outside OpenID Connect? Which leaves the question how to resolve opaque tokens from API requests against identity details (JWT) for use in our API/services?
If you use opaque tokens, OIDC/OAuth 2.0 has several endpoint (like UserInfo) to get further information about the user. You can also use Introspection endpoint to know the validity of the token.
(Scenarios 3 and 4): I am not sure how you plan to use this - But for any non-interactive client(which is acting on its own and not behalf of user), you should use client credentials flow.
If the client want to act on behalf of user, you should enable a way for the user to approve this behavior.
I recommend anyone who is interested in OpenID Connect (OIDC) to look into OAuth2 specification. Since OIDC is built up-on OAuth2, it inherits many fundamental features.
First thing to note is Implicit flow does not return a refresh token.
The implicit grant type is used to obtain access tokens (it does not
support the issuance of refresh tokens) and is optimized for public clients known to operate a particular redirection URI
If you want to rely on refresh tokens, then you MUST consider this fact.
Can this be done purely with one of the tokens issued by the OpenID Connect implicit grant type?
It depends on the design and exact requirements. But you can indeed build the authentication on top of Id token and use access token for API calls. To validate access tokens, you can use introspection endpoint from API endpoint.
Can an access token be issued in a long-lived (no expiry, only invalidated by deleting from the system) way and then be exchanged by the client against an ID token?
This could be possible depending on the configurations of identity provider expose. But by specification, this should not be done for a client who use implicit flow. And simply because of security reasons. This is the very same reason why implicit flow does not return a refresh token. On the other hand, refresh tokens are the one which can live longer. For example, Google's refresh tokens never expires (reference - 8953983).
Or is the refresh token the thing to use for exactly that?
As mentioned previously, refresh tokens can long-lived. And it can be exchanged for a fresh access token. Returning of the id token for a refresh token will depend on identity provider implementation. For example, Azure AD do return an ID token for refresh token response. But going beyond that, the identity provider can offer a user info endpoint. A good article can be found from this link
Or do we have to solve this outside OpenID Connect? Which leaves the question how to resolve opaque tokens from API requests against identity details (JWT) for use in our API/services?
ID token indeed help to authenticate the end user from client side. But when it comes to validate user from API endpoint, you can think about using introspection endpoint or a user info endpoint. But be mindful, some identity providers do not provider introspection endpoint. At the time of writing this article Azure AD do not expose one (reference - 43378748) but do provide a user info endpoint.