Client application and token authentication/validation OAuth - javascript

I am trying to implement OAuth with my javascript client application.
I already have the server up and running.
My workflow is as following:
Open app
Check if token is present
Validate the token
If not present or not valid go to oauth server for the token
Get back to app and repeat 2 and 3
I everything is ok show my app
I am not sure how to implement point 2. I understand that I need to make another call to the server for this but where is the validation endpoint?
I only have /authorize, /user and /logout
Also how should the request be formed? Do I attach token as a GET parameter and thats all?
What if somebody intercepts valid the token?

Depends on your application, but since you have a javascript web application, that most probably can't keep it's credentials secret, you'll need to implement the Implicit Grant as stated in the OAuth 2.0 spec. If however your application CAN keep it's credentials secret, you should implement the Client Credentials Grant (server side application) because it's more secure.
I am not sure how to implement point 2
You should store your access token somewhere in your web application, for instance in localStorage.
The first time a user will access your web application, the user will have NO access token and NO session with your authorization server. Your web application could see if you have an access token by doing something like:
if (!localStorage.getItem('accessToken') {
window.location.replace('https://your-authorization-server/authorize?response_type=token&client_id=<CLIENT_ID>&redirect_uri=<CALLBACK_URL>&scope=<SCOPE>');
}
If there's no access token, you'll need to redirect to your authorization server so that the user can log in with the authorization server. After the user has logged in, the authorization server will redirect the user back to your web application (after the user has granted permission to whatever resource your web application likes to access on behalf of said user) with a valid access token. This access token must be exposed as a hash fragment named access_token, i.e:
https://web-app.com#access_token=123456789X
Now your web application can extract the access token and store it somewhere.
I understand that I need to make another call to the server for this
but where is the validation endpoint? I only have /authorize, /user
and /logout
Your authorization server requires a token validation endpoint. This endpoint will be used by your web application to validate said token (the one you stored somewhere, for instance localStorage). When this endpoint is called with an access token and it turns out the token is valid, the user can continue, otherwise the user will be redirected to the authorization server. If the user already has a session with the authorization server, the user will be redirected back immediately with a new access token, otherwise the user needs to authenticate (login) first.
Also how should the request be formed? Do I attach token as a GET
parameter and thats all?
Some send a GET request with the access token as a url query parameter, others send a POST request with the access token as the payload of the request body.
What if somebody intercepts the valid token?
Always use https and your access token should be valid for a limited amount of time.
Something to keep in mind is that because your application can't keep it's credentials secret, you need to Implement the Implicit Grant, this means you immediately receive the access token when the authorization server authorized the web application based on Client Id and domain. As opposed to Client Credentials Grant where you first receive an Authorization Code that needs to be exchanged for an access token. When using Implicit Grant you can NOT use Refresh Tokens. This means the user NEEDS to go through the entire flow with the authorization server to obtain a new access token. But this isn't really a big deal, because the user will already be logged in with the authorization server, resulting in an immediate redirect, so when implemented correctly in the web application, the user won't notice.
This is just covering it in broad strokes, it really helped me (and I advise you) to read the OAuth 2.0 spec. Hope this helps you out a bit, OAuth is a complex subject!

Related

How are JWT refresh tokens meant to be sent from the client to the backend?

It is my understanding that, as someone that has recently started using JSON web tokens that, once an access token expires, a new one may be generated using a refresh token.
I currently have some middleware on my server configured such that, if a JWT verification fails, it uses the refresh token to generate a new access token and then attempts the verification process again. If this succeeds, it sends a response with the new access token attached. If it fails, it sends a 401 error.
For this to work, however, the client must send both the access and refresh tokens. My fetch requests are currently configured such that they send the access token under the Authorization header as Bearer [token].
However, when reading the JWT docs, I have come across nothing that refers to the correct manner in which to send the refresh token. A brief search returned that it should be sent in the body of a POST request, however, given I am currently sending both tokens in all fetch requests I make, this would not work for GET requests.
Should I be sending both tokens in all requests? If so how should I send the refresh token in a GET request. Given it is stored in the client cookies, I have considered extracting it from there, though I'm curious if there is a better/more generally accepted method.

Simplest way to get current user logged in Keycloak

I have implemented a really simple keycloak integration on my maven java web app.
Assuming I am calling a url directly for the keycloak log in page .
http://localhost:8180/auth/realms/myrealm/protocol/openid-connect/auth?client_id=myclientid&response_type=code&scope=openid&redirect_uri=http//localhost:8080/mypage.html
After entering my username & password on success i am being redirected on mypage.html , the url is like this
http://localhost:8080/mypage.html?session_state=c9482da3-50ff-4176-bf3c-54227271c661&code=5d4aebda-54d8-41ad-8205-c4d7e021770f.c9482da3-50ff-4176-bf3c-54227271c661.d5c1b6ac-c427-46da-8509-f2689849103b
If I break this down its
http://localhost:8080/mypage.html?
session_state=c9482da3-50ff-4176-bf3c-54227271c661&
code=5d4aebda-54d8-41ad-8205-c4d7e021770f.c9482da3-50ff-4176-bf3c-54227271c661.d5c1b6ac-c427-46da-8509-f2689849103b
What would be the simplest - easiest way to get the user currently logged so i can display it's name ?
Looking at the requests you have made you have not completed the OIDC code flow.
I'm assuming that your java application is acting as the OIDC client, in which case it will need to exchange the authorization code for access, id and refresh tokens by calling the token endpoint of your realm.
e.g.
POST /auth/realms/mmyrealm/protocol/openid-connect/token HTTP/1.1
Host: server.example.com
Content-Type: application/x-www-form-urlencoded
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
grant_type=authorization_code&code=SplxlOBeZQQYbYS6WxSbIA
&redirect_uri=https%3A%2F%2Fclient.example.org%2Fcb
A description of the Token Request
The simplest way would be to use a Java OIDC Client or OAuth2 client to do the authorisation and cod exchange for you and provide OAuth2/OIDC token primitives for you to code against.
Have a look at:
Scribe Java OAuth2 client
Nimbus OIDC SDK
The details of the user will be in claims within the tokens returned by the token endpoint, if you are including the user claims in your tokens.
Edit:
The OIDC Authorization code flow is one of the OIDC authorisation flows. It provides the benefit of not exposing any of the actual tokens to the user agent - e.g. web browser - and allows the oidc client to authenticate with the token server before exchanging the code for the OIDC tokens
At a high level the following occurs:
OIDC Client makes an authentication request
Client authenticates - this could be an end user
Authorisation server returns an Authorisation code - on a redirect - to the client
OIDC Client retrieves Access, ID and Refresh Tokens from the authorisation server's token endpoint
If needed User info is retrieved from the UserInfo endpoint or thge access token is inspected using the introspect endpoint
Details of the actual user will be in claims with in the ID token, which is a plain JWT.
Keycloak allows you to embed the claims in the Access token too.
After authentication with Keycloak you will be redirected back to your web applications redirect URI.
As per your breakdown
http://localhost:8080/mypage.html?
session_state=c9482da3-50ff-4176-bf3c-54227271c661&
code=5d4aebda-54d8-41ad-8205-c4d7e021770f.c9482da3-50ff-4176-bf3c-54227271c661.d5c1b6ac-c427-46da-8509-f2689849103b
Your requst handler will need to extract the code from that request and then make another call to keycloak to exchange the authorisation code for Access, ID and refresh tokens
e.g.
POST /auth/realms/myrealm/protocol/openid-connect/token HTTP/1.1
Host: localhost:8180
ContentType: application/x-www-form-urlencoded
Authorization: <whatever method your oidc client is usingL
grant_type=authorization_code&
code=5d4aebda-54d8-41ad-8205-c4d7e021770f.c9482da3-50ff-4176-bf3c-54227271c661.d5c1b6ac-c427-46da-8509-f2689849103b&
client_id=myclientid&
redirect_uri=....
Ideally you have a route handler for accepting the tokens - maybe a tokens enpoint that also accepts query parameters that indicate the original uri requested so that you can redirect back to that if this is a user facing web application.
If it is completely programatic then you can achive all of it using the nimbus sdk.
The has a good summary of the various parts of Authorization Code flow
https://rograce.github.io/openid-connect-documentation/explore_auth_code_flow

Two token security: JWT/Oauth2 in regular cookie plus OAuth2 refresh token in HttpOnly cookie?

I'm exploring JWT and OAuth2 for a Javascript Single-Page-App which will make calls to a backend server-side API. I've come up with a security process that involves using two tokens and gives me the advantage of avoiding the need to have an additional server-side session storage:
The first time the client JS app is loaded up, user sends username/password over SSL to OAuth2 server. The server will set a cookie (normal cookie that is readable by client, without any HttpOnly flag set) that contains a JWT with an OAuth2 access token inside it's claims (along with some other non-confidential data in the JWT claims, ie. user's first/last name, country, role/permission). The server will also set a HttpOnly cookie that will contain the OAuth2 refresh token.
The cookies set by the server will be included on every request from the client automatically (always over SSL), so the server will receive the JWT (see step 3) and both confirm the signature and confirm the OAuth2 access token. The server will also confirm the refresh token. Since the server is checking the access token and refresh token against the OAuth2 database on each request, this gives us the ability to revoke access (which we would not be able to do with the JWT signature alone). We can do a "hard" revoke which revokes both access and refresh token. And we can do a "soft" revoke which just revokes the access token (for instances where perhaps some data that we keep in the JWT claim gets updated, ie. user changes their name or country or role). A soft revoke would be invisible to the client end user (it wouldn't disrupt their logged in status).
In step 2 above, the server will actually look for the JWT in a specific header set by the client (instead of the cookie set by the server). For example, the client JS app will read the JWT from the cookie and then set the JWT in another part of the header. By requring the client to explicitly set a header key/value containing the JWT shows that the client was able to read it's own cookie, thus preventing against XSRF (cross-site request forgery).
The HttpOnly cookie that contains the refresh token ensures we are protected against XSS (ie. some malicious javascript that sneaked its way onto our client). If our JWT was stolen, access still wouldn't be granted because the refresh token was not also seen or stolen by the JS.
With this approach we get all these benefits:
We don't need a server-side session storage. Since we are hitting an OAuth2 server then we can simply just include some extra data in the JWT that we return (non-confidential data). We wouldn't need to re-query/refresh the data in the JWT every time, but perhaps only when the OAuth token is revoked (ie. was revoked when some user data was changed that we include in the JWT's). No need to tackle the storage/scaling requirement that comes with using sessions. The client JS app can use this data like any other app would normally use sessions. For instance I can display a user's name on every "page" in the app. We could also just use websockets, but the JWT is a good backup place for adding some data if we need it.
We are protected against XSRF.
We are protected against XSS.
We can revoke access and also log users out (which is not easily possible with JWT alone).
SSL prevents man-in-the-middle attacks.
The JWT adds a little extra security hurdle for attackers to pass versus just a normal JSON object serialized in the cookie. The attacker would need to get the server-side key for signing JWT's (in addition to OAuth access). The JWT is also a standard, so easier for a trusted developer to work with.
The JWT can be easily passed down to other micro-services sitting behind the OAuth layer to use service-to-service. We can pass it around as "session like" data access to all the services on a request. If a service want's to change something in that data, then they can inform OAuth2 server and it will "soft" revoke the user's current JWT (not really much different from the process with a session storage) and provide a new one.
I haven't exactly seen anyone detail a security process like this yet. Many I see seem to only talk about using JWT with an OAuth2 access token inside and don't elaborate much more. So my question is, does this approach indeed provide the benefits I listed above? If not, what am I missing here and what security hole have I not covered for?

Using refresh tokens between sessions

I am implementing OAuth2 in my PHP web application. Access tokens are distributed to javascript web clients with an expiration of 1 hour, and a refresh token is provided. If the client quits the browser for more than 1 hour the next time they navigate to my web application the access token is no longer valid during the initial request to the resource server. The resource server then returns a unprotected page.
In the event I have:
Expired access token
Valid refresh token
New session
Should the resource server return a unprotected page, and the client using javascript attempt to refresh the access token and if successful force the page to reload? Is that common? Or am I missing something so the resource server isn't called twice?
Currently the client passes the refresh token to the resource server, so technically the resource server could refresh the access token. But, this doesn't seem to be allowed by RFC 6749 which seems to indicate the resource server should never see the refresh token.
"Refresh tokens MUST be kept confidential in transit and storage, and
shared only among the authorization server and the client to whom the
refresh tokens were issued."
In any case, as you indicate, one never passes a refresh token to the Resource Server. The refresh token is only ever presented to the Authorization Server. But:
In-browser clients such as Javascript clients should use the Implicit grant to get their access token. In that case there is no refresh token that is issued. That should not be a problem with in-browser clients since the user is present in that case, so no refresh token is needed to get a new access token: the user will just authenticate to the Authorization Server again, hopefully leveraging an existing SSO session for that.

Passing credentials with Ajax load to Web API

I have an MVC site that uses authentication and authorization successfully. I am trying to query an api portion of the site using jquery and the load method. I have attempted to then use
User.Identity.GetUserId()
and this fails, as the request is not authenticated. The page with the ajax request is sucessfully logged in. Is it possible to access its authentication token and pass this with the load request, or do I need to generate a new token in javascript?
EDIT: After some more research, I have found that this line in the WebApiConfig file:
config.SuppressDefaultHostAuthentication();
Is what is disabling the cookie validation for ajax requests. It makes it so only the token method is evaluated. By default MVC uses cookies, and web api uses tokens. I was trying to utilise two different authentication schemes. As the cookie is sent automatically with the ajax requests, the User.Identity is then filled. This answers my original question.
However, this is considered insecure and allows for CRSF attacks. Therefore, token is desirable.
So, reworded, can you use an existing authentication cookie with the /token endpoint to generate an authentication token?
I think you can do the following steps to achieve your goal:
Read authentication cookie on the client using jquery cookies plugin or whatever.
Create an Web API endpoint to handle AJAX authentication which accepts cookie as a body parameter.
Parse authentication cookie, get user information from it and return a token.
Use generated token for subsequent reqeuests.
Ive found a workable solution with the minimum amount of effort.
The ApplicationOAuthProvider is the default provider. It provides an endpoint at /token that you can call with your username and password. In return it provides an authorization cookie, and more importantly a bearer token in the body of the response.
The login flow for the user is unchanged. They visit a log in form, and enter their credentials. This then calls the /token endpoint transparently, returning the response token and cookie. This token can then be saved using javascript to the local or session storage:
localStorage.setItem("token", "value");
This can then be retrieved for any pages loaded in the same browser session. You load this value and pass it in the headers of the ajax request, which then authenticates with the web api.
Use session storage if the user specifies they should not be remembered, otherwise local storage will mean the token is available more often. You do have to check both stores however, and there is a risk the token is invalid from expiration. If this occurs as signalled by an authorization error in the ajax request, you can easily display a message and redirect the user to the sign in page.

Categories

Resources