Is there a standard HTTP Authentication scheme which is appropriate to use with OpenID Connect? The scenario I have in mind is as follows:
An HTTP Service requires authentication of users. One of the possible authentication methods is to use a federated identity from a 3rd party OpenID Provider. The Service is registered with the 3rd party OpenID Provider as a confidential client, and possesses a client_id and a client secret.
When a user tries to access the HTTP Service, the server responds with a 401 Unauthorized and a WWW-Authenticate header containing information about how to initiate an authentication request with the OpenID Provider:
WWW-Authenticate: OpenIDConnect realm="MyService", client_id="1234-5678", authorization_url="https://provider/authorize"
The client contacts the authorization endpoint, authenticates, and then obtains an authorization code. The code is then specified in a subsequent request to the Service via the Authorization header, e.g.:
GET / HTTP/1.1
Authorization: OpenIDConnect client_id="1234-5678", code="AAABAAA..."
The Service will use the code to obtain an ID Token from the OpenID Provider and establish an authenticated session with the client, e.g. by setting a cookie or returning a new set of credentials to use for subsequent requests.
The OpenIDConnect scheme is something I made up for this example. I have tried searching for a standard way to do something similar, and the absence of results has left me with the following possible answers:
I have not searched hard enough.
What I am trying to do is misguided and wrong.
Everybody implements their own custom authentication schemes for this purpose
I think you did not know where to look for in the first place. Since RFC 7353, authentication schemes in HTTP are subject to the IANA HTTP Authentication Scheme Registry. In said registry, you are going to find the OAuth scheme which is subject to RFC 5849, section 3.5.1 and is looking a lot like what you are looking for. That being said, however, this is for OAuth 1.0. OAUth 2.0 is resorting to the Basic (RFC 6749) and Bearer (RFC 6750) schemes.
This in its entirety is concernig authorization (via OAuth). OpenID's realm is authentication, though. You may want to look at What's the difference between OpenID and OAuth?
Related
I have written a web application which makes REST API calls to a message broker. The message broker contains already written REST APIs to which can be used to get message broker data. The message broker is written in a way in which each REST API call sends the user name and password which is encoded with base64. I need to make a login to my web app and authenticate it with OAuth.Does anyone know how to do this? How to authenticate the REST APIs with OAuth?
Step 1: Add OAuth 2.0 to your web server. This is very standard with lots of libraries available. You did not specify the Identity Provider that you will use (Google, Facebook, Auth0, Okta, etc), but each vendor has documents and libraries for you to use in your desired language.
Step 2: Add an Authorization Header to your API calls. The standard method is to add the HTTP header Authorization: Bearer access_token when making an API call.
Step 3: Add OAuth token verification to your API. When your API receives a request, it extracts the Authorization header and verifies the Bearer token. How this is done depends on the Identity Provider. For example, some vendors provide a Signed JWT (which you verify with the vendors public certificate), others provide an opaque access token (which you verify by calling the vendor's token endpoint). Add internal caching of tokens so that you don't need to verify on every API call.
If you understand OAuth 2.0 the above steps are straightforward to implement. If you don't Oracle has a set of videos which are excellent for getting started understanding OAuth.
Oracle Cloud Primers
If your desired OAuth implementation does not require users logging in and is a server to server service that you control on both ends, then you can use just part of OAuth which is Signed JWT (JWS). You create a Json data structure with your desired content and sign it with a private key. This creates a token that you can use in the above steps. You would then validate the token using your public key. You can use self-generated keypairs generated by OpenSSL or similar products for your signing and verification.
I'm currently trying to retrieve a user token from the keycloak token endpoint using a POST request (instead of using one of the designated adapters). I have set up a keycloak realm and added my own machine as a client. In the documentation the Token Endpoint is described as:
/realms/{realm-name}/protocol/openid-connect/token
As far as I have read in the openid specification, I will need to set the body parameter grant_type=authorization_code as well as the parameters code and redirect_uri. I will also need to set the Authorization header, for which I will need a Basic Token.
So far I will get the response:
"error": "unauthorized_client", "error_description":
"INVALID_CREDENTIALS: Invalid client credentials"
Where do I get the Basic Authorization Token from? I expected that I need to provide a username and a password, since the JWT token is what I'm trying to recieve as response. Do I need to set the redirect_url if I just want to request a token?
Keycloak offers more than one way to retrieve a user access token, following the OpenId Connect spec. Here you have the steps to do it for Authorization code flow (the one recommended for web applications) according to the openid connect spec: https://rograce.github.io/openid-connect-documentation/explore_auth_code_flow
Basically, if you're not using any adapter, when detecting a request to some protected resource you should:
Perform a redirection to the keycloak login page (keep in mind keycloak uses the REALM entity, so you'll need to specify it too):
HTTP/1.1 302 Found
Location: https://mykeycloakinstance.org/auth/realms/demo/protocol/openid-connect/auth?
response_type=code
&scope=openid
&client_id=s6BhdRkqt3
&state=af0ifjsldkj
&redirect_uri=https%3A%2F%2Fclient.example.org%2Fcb
You'll need to keep the state value in the client, as it needs to survive the redirection process:
It is recommended that client’s use this parameter to maintain state
between the request and the callback. Typically, Cross-Site Request
Forgery (CSRF, XSRF) mitigation is done by cryptographically binding
the value of this parameter with a browser cookie.
You don't interact with username/passwords. The keycloak authentication page does. Once the login is successful, it will redirect to your page with a valid code:
HTTP/1.1 302 Found
Location: https://client.example.org/cb?
code=SplxlOBeZQQYbYS6WxSbIA
&state=af0ifjsldkj
Here you'll need to either check that the state is the one you originally sent (you may need to track it through web session, using cookies) and also to obtain the token using that code. You do a POST to the authorization endpoint with this code:
POST /auth/realms/demo/protocol/openid-connect/auth HTTP/1.1
Host: https://mykeycloakinstance.org
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
This is the flow in summary, I haven't tested the code myself, so use it as an example and don't hesitate to fix it if you consider ;-)
See also:
What are Keycloak's OAuth2 / OpenID Connect endpoints?
I am doing oAuth logins on my site. When I am doing facebook, I found I can dynamically give a return urls. but when I am doing google, I found the return url I pass to google must match the settings I did on google.
Why it is different in both oauth providers, how about other oath providers?
What is the best way to implement dynamic return url?
Thanks,
Ron
Assuming you're referring to the redirect uri in OAuth 2.0
From RFC 6749 (The OAuth 2.0 Authorization Framework):
The authorization server MUST require the following clients to register their redirection endpoint:
Public clients.
Confidential clients utilizing the implicit grant type.
The authorization server SHOULD require all clients to register their redirection endpoint prior to utilizing the authorization endpoint.
The "redirection endpoint" is the redirect uri.
Any client that uses the authorization code flow together with a client id and client secret can allow the user to specify the redirect uri. This is because the authorization code which is passed on to the redirect uri is useless unless you also have the client secret.
If the client isn't able to keep a secret and uses the implicit access token flow, e.g. a javascript only web application, the redirect uri has to be registered to make sure that the access token doesn't fall into the wrong hands.
OAuth providers can also choose to require the redirect uri to be registered even when using the authorization code flow as an extra security measure.
As for implementing dynamic redirect uri that depends on the library you're using for oauth on your site.
Folks,
What is a simplest way to track consumer applications accessing RESTful API services inside department.
We do not restrict access - no authentication/authorization - open for invocation, trusted environment.
No tools like OAuth AuthZ servers or API management yet... but might be heading there at some point.
For now we thought to request consumers just to include some custom HTTP Header like X-Client-Id and log it on the server side for stats etc..
But knowing that in the future we might want to switch to more standard ways of doing things ... what would be best alternative to have to change less code in the future ?
Have the "clientId" in the Authorization: OAuth token (like access token)
Have JWT token in the Authorization header (looks too much - signing,base 64 etc for simple client id tracking ...)
Any ideas would be appreciated
We recently implemented this for one of our REST platforms and we used a combination of BOTH the points you mentioned, meaning Authorization header & JWT token. Although, JWT is ONLY for authentication and GETTING an access_token (oauth token) which is later used with calling actual resource apis. I will discuss how we handled this situation and you can decide on how you want to implement it.
1) Authentication
Client sends a JWT to your authentication service (/api/oauth2/auth). (If you want more reading on JWT, you can read here and here of how JWT is implemented by google and how you can use spring-security-jwt libary to handle all the signing and encrypting/decrypting). You get the "clientId" out of JWT after decrypting and verifying the signature and after server does all the authentication, you respond back with a 'refresh_token' and an 'access_token'. Server will save the access_token as well and map it to the clientId so that when client makes requests using access_token, you can know which client is making the request. The access_token expires in some time (ideally in an hour) and when it expires, the client uses the 'refresh_token' to get a new access token by posting refresh_token to some refresh token url (/api/oauth2/auth/token)
2) Authorization
Client takes the 'access_token' and uses the access token to make all the subsequent requests on all other apis (/api/*). Ideally, the access_token is sent as a part of the "Authorization" header. Server uses request filters (if you are using JAX-RS, you can use something like ContainerFilterRequest to add filters to specific url patterns and intercept them) to filter EACH request and parse out the Authorization header value. You will get the access_token from the header and from the access_token you can get the clientId that you mapped in step 1). You can do other authorization logic in the security filter and if everything goes through, you can use this information to LOG that clientId and the request that the client made.
This way you can kill 2 birds with one stone : Implement a security layer & log the information about customers (what calls they are making, how many time etc. etc.). In case you don't want to implement security filter just yet (as you mentioned it might be in the future), for now, the clients can just pass on the "clientId" (base64encoded or not, upto you) as a part of "Authorization" header. If all the calls are from a "trusted" network, it should be ok, although not as secure. This way, when you ACTUALLY implement a JWT and Oauth based security layer, all you have to do is change your ContainerFilterRequest logic to parse out access_token instead of client id (as mentioned in step # 2).
I hope this helps ! For more information on security filters you can have a look at this answer: Basic Authentication of a resource in Dropwizard. It says dropwizard, but it mostly talks about JAX-RS.
To implement full AuthN/AuthZ layer for consumer tracking would be an overkill for now.
We thought to use either to Authorzation header to pass custom client_id token:
Authorization: Custom <Client_Id>
or to use some limited version of JWT (no signatures as there no intent to validate them)
as access token
Authorization: JWT <JWT>
Where JWT could be:
{"alg":"none","typ":"JWT"}
{
"iss":"Client_ID",
"aud": REST Service URI,
"iat":1328550785
}
I do not see description of access_token format in the specification https://datatracker.ietf.org/doc/html/rfc6749#section-1.4
Are there any contraints to use JWT as access token?
Overview
I am developing a mobile application using PhoneGap with REST API for the backend. The REST API won't be utilised by third-party developers, but will be application-specific, so there is no need for oAuth to be implemented. Hence, I am planning to use Basic Authentication where in the User enters their Username/password to access the API resources. All API communication will be on SSL.
Basic Authentication with Token
Instead of letting the application store the username/password and send it with every request to the API, I would rather authenticate username/password on the first login request and send a GUID token back. The client stores this GUID token and sends the token back to the API with each request through the Authorization header, like this:
Authorization: Basic e1d9753f-a508-46cc-a428-1787595d63e4
On the server side, the username/GUID combination will be stored on the server with a expiration date along with device settings. This will allow to keep track of the number of devices a user has logged in from as well as expire the session once the Guid has reached expiration.
Does this approach sound reasonable and secure?
There is no need for you to create custom headers or authentication schemes at all.
The Bearer authentication scheme is designed exactly for your use case:
Authorization: Bearer e1d9753f-a508-46cc-a428-1787595d63e4
Basic authentication must be as follows:
Authorization: Basic base64EncodedUsernameAndPassword
where base64EncodedUsernameAndPassword is equal to the output of:
base_64_encode(username + ':' + raw_password)
Do not use Basic if the trailing text value is not the above exact algorithm.
If you just want to put whatever value you want after the scheme name, use the Bearer scheme - that is what it was invented for.
Warning
While you can use a simple GUID/UUID as your token, this isn't really a secure token. Consider using a JWT instead. JWTs can be digitally signed and assigned a TTL so that only the server setting it can a) create it and validate its authenticity and b) ensure it is not used longer than is allowed. While this may be true of your data stored based on the GUID, the JWT approach does not require server state - so it scales far better - and accomplishes the same thing.
The general "Authentication with Token" approach is very good but you shouldn't try to make Basic Authentication work in different way than it is supposed to (after all it is a defined standard). You should rather use your own header for authentication purposes. You can find a very good description of such scenario here:
Making your ASP.NET Web API’s secure