I am adding JWT Auth for a completely new frontend to a legacy Rails backend.
Upon HTTP request, it seems most sources suggest I send the token back to the server via Bearer Header.
Why? What is the additional value of sending via header (bearer or basic). What can't I simply pass the JWT back to the server via .json and authenticate the token from there.
What benefit does an Authorization header give me, and moreso, what does a Bearer Authorization header give me?
I can of course simply follow everyone's example, but want to understand why. The bearer docs are verbose and hard to understand what I'm gaining over simple sending the JWT as part of the data in the request.
Thank you.
You can technically send a json body on each request with the JTW but that would be non standard behaviour (for instance, GET requests should not have a body via the spec).
A more standard way would be to provide an Authorization HTTP header.
The Authorization header is not specific to JWTs and its role is to specify an auth scheme between the client and the server.
Another way would be to include the JWT inside a cookie but that would make the behaviour browser specific while the HTTP header can be sent by virtually any HTTP client.
P.S
Bear in mind that contrary to Auth cookies which are sent by the browser automatically the Authorization header needs to be set by the client explicitly.
Related
The rfc explicitly requires that token is passed in body only if content type is form-url-encoded
What the reason behind it? Why not permit multipart?
Workarounds:
This poses a problem for file uploads where the browser sets the content type to multiparty/form-data
The most common solution is to pass the token in the query string, which is insecure for logs or appearance in history.
The preferred method is to use the Authorization header to send the access token. The body and URL variants are in the spec to enable OAuth to clients which cannot, for some reason set the HTTP header value. In order to limit the possibilities the server would have to process the standard limits usage to only form-url-encoded. You can read some more about the problems that can arise from this in this answer: Why do we prefer Authorization Header to send bearer token to server over other techniques like URL encoding
In short - it would have been much more complicated for the resource servers in order to support receiving an access token using different content-types. I believe this the main reason behind this decision (although there might be some security implications I'm not aware of).
so generally, the best solution would be to pass the token in an Authorization header, instead of the body or URL.
While learning how OAuth2 works, I cannot figure out why there is a separate step to retrieve Access Token?
A separate step means:
an extract HTTP request
passing Client Secret in the URL
I'd expect the Access Token to be generated in the "authorization" step, encrypted with using the Client Secret, and returned back when redirecting to the Callback URL. Then the client application would decrypt it and use it straight await without issuing an extra HTTP request.
I guess there are some reasons behind having an extra step, and I'm just not aware of them. I hope you can explain the reasons in your answer.
I'm assuming you're talking about the Authorization Code flow and not the Implicit flow, which does return a token directly.
The Authorization Code flow is designed to work with potentially unencrypted servers via a callback URL (this was designed years before Let's Encrypt and the relatively recent encrypt-everything push). Thus, the URL could be intercepted by any intermediate routers/proxies, and sending an access code as part of the callback URL in that environment is a Bad Idea.
So instead, the authorization code is sent. Then the client exchanges the authorization code along with its client secret for an access token. The authorization code can be intercepted, but in the Authorization Code flow, the client secret is actually secret and not known outside your server, so any intercepted authorization code is useless on its own.
These days, encryption is common and free, and unencrypted flows are strongly discouraged. The extra call remains part of the Authorization Code flow for historical reasons.
I have 2 internal Rails services, which need to speak to each other.
I need an advice how to make it secure enough and with minimum effort.
Currently service A sends Authorization HTTP header to service B, which contains secret token. Simple HTTP Token-based method, nothing special. But I also need somehow to communicate a user token, so service B will know, which user is talking to it.
My current solution is following:
send Authorization Token token=blabla user_token=blabla2
use existing in Rails methods to parse it
identify user by provided user_token
inspired by this StackOverflow post
Alternatives:
Amazon way with something like: Authorization: MY-APP-V1 Token=blabla Credential=user_token, but I need custom parser for it.
Custom HTTP header like X-USER-TOKEN, but seems like RFC is not in favor of this idea.
Your proposal or suggestion
Thank you very much for any help.
I'm curious as to why the user token is not enough, can you elaborate on this?
But assuming you want to continue with the double-token approach, something like JWT could be used to encode the user token with the secret token. That way you will just have 1 token and can send it simply as Authorization: Bearer xxxxxx.
I'm a newbie to this stuff so downloaded the samples which is all fine and I thought I could see what was going on and what I needed to do. However, got a bit stuck for no obvious reason so I wondered if anyone could maybe give me some hints.
I'm trying to engineer Cognito authentication and identity into an old Apache Struts 1 legacy web application written in Java, so all the activity needs to be server-side. Using the Cognito https://xxx.auth.xxx.amazoncognito.com/login? URL I can successfully authenticate and get an auth code back using this URL providing my client id, redirect URI and response_type=code so all good thus far.
If I then create an HttpClient (as per the sample code in Github) and call the token URL https://xxx.auth.xxx.amazoncognito.com/oauth2/token and write various parameters to the request body (grant_type=authorization_code, client_id=as previously, redirect_uri=my URI and code=auth code just returned), I get an "unauthorized_client" message returned. But the code is valid albeit for authorization, and the client_id is correct because I used it previously.
My log:
Cognito following successful signin, continuing to url http:[redacted]/passport/CognitoHandlerSignIn.do?code=62eeb0b1-a76b-489b-bd28-e42023a497bd
(this was the /login succeeding)
Callback from Cognito received
(following is the log dump of the /oauth2/token URI called to)
Cognito token signin URL is https:[redacted].amazoncognito.com/oauth2/token
HTTP request header, added Authorization=Basic M29wcGR0azdpYzF2YjloNGd0OTQzNXYxcmI6MW9mMmFsaWNzZGR2dHZ1NmFkOHRuc2s4cnJ0cXEyYm0yc3RqbG1mcmkyamhkdXBubG1wMw==
HTTP request header, added Content-Type=application/x-www-form-urlencoded
HTTP request body, added grant_type=authorization_code
HTTP request body, added
redirect_uri=https%3A%2F%2F<redacted>%2Fpassport%2FCognitoHandlerSignIn.do
HTTP request body, added code=62eeb0b1-a76b-489b-bd28-e42023a497bd
HTTP request body, added client_id=[redacted]
HTTP request is sun.net.www.protocol.https.DelegateHttpsURLConnection:https:
[redacted].auth.eu-west-1.amazoncognito.com/oauth2/token
HTTP Json result=<{"error":"unauthorized_client"}>
org.json.JSONException: JSONObject not found.
at org.json.JSONObject.get(JSONObject.java:454)
at
What's wrong with this picture? I tried also adding client_id, code as URL parameters but I just get an "invalid_client" message instead.
I also tried using the /oauth2/token URI directly from the Struts app to provide a token but it returns the id_token using # rather than ? in the parameter list so it is client-side only and hence can't be intercepted by the Struts app and so will be a pain to forward to the server, but I could write some Javascript to do it if I had to. It doesn't seem the path of least resistance, though, as it seems wrong that the pure Java server side call doesn't work so I must be doing something wrong which isn't obvious to me.
Question
If you would use a similar setup as the following examples:
Simple WebAPI
Javascript OIDCClient and usermanager
Would it be possible to protect other clientside files from being accessed? Say for example i have a directory with certain files which you need a certain role to be able to access them.
Would it be possible to protect my SPA from being accessed before logging in?
Or is there a better solution which would have you end up with a protected api, folders/files on a server, SPA and a silent renew mechanism like there is in the OIDCClient?
#dmccaffery helped me out by answering my question, here is his answer for those of you who are interested.
To summarize using the OIDCClient for an SPA is certainly the way to go. Exposing stuff which needs authorization should be done by using an API. Protecting parts of your Angular App can be done using a Route guard.
The way it works is as follows:
The access token is either a JWT or a bearer token (usually) and is
added by the oidc client to every HTTP request in an authorization
header — when a web API receives a reques, the bearer token
authorization middleware will parse this HTTP header and will call the
token introspection endpoint (and potentially the user info endpoint)
to have the token validated and the users claims retrieved… if the
token was manipulated by the client, it will not be valid, and an HTTP
error will be returned (usually a 403). If the token was valid, a
claims identity is created and assigned to the http request context.
The API will now have a thread with an identity already assigned to it
that represents that user.
Also he pointed out 2 pluralsight courses which would probably be useful:
https://www.pluralsight.com/courses/building-securing-restful-api-aspdotnet
https://www.pluralsight.com/courses/oauth2-openid-connect-angular-aspdotnet