I have Keycloak for authentication and authorization of multiple applications (a web page and a REST API). From my understanding the flow for the web page when using OAuth2 authentication_code grant type is as follows:
In this flow, in the second step (the one in red) the resource owner logs in because she/he were redirected to the login page of Keycloak. This flow is clear to me and is working well.
But, with the REST API I don't know what is the process to authenticate and authorize the user (resource owner), because there isn't a browser to redirect him to the login page of Keycloak. So, I tried with the password grant type and it worked, but then I realized that this grant type is deprecated. So I tried again with the authorization_code grant type but can't make it work. I am trying to get the token using the following request:
URL: http://localhost:8080/auth/realms/somerealm/protocol/openid-connect/token
Body:
username: someuser
passwoord: somepassword
grant_type: authorization_code
client_id: someclient
secret: somesecret
The problem is that I am receving the following response:
{
"error": "invalid_request",
"error_description": "Missing parameter: code"
}
I know I have something wrong in the request (and in my understanding of OAuth2), but I have read a lot and can't discover what it is.
API (backend) doesn't need any login flow usually. It just needs to verify token and then it executes requested operation or it denies it (response code 401 - problem with authentication / 403 - problem with authorization). It doesn't redirect to auth server.
Client, which is using API must obtain token before API request. It can be done by the frontend (e.g. SPA with The Authorization Code Flow + PKCE) and then frontend maintains state (token refresh, error codes from the API, ...).
If you don't have any frontend, then procedure how to get token must be part of API specification. For example see swagger doc: https://swagger.io/docs/specification/authentication/oauth2/
The Client credentials flow should be used machine to machine authentication, so it's not a solution if you need to know user identity.
With the authorization_code grant type you have to spawn a browser in some way.
password is unfortunately deprecated, but the recommendation is to use client_credentials for these cases now. I hope this decision get reversed before OAuth 2.1 is released.
Related
I am building an Angular SPA app and using Okta as an Idp. since its an SPA so I think I need to use Implicit flow. I have two queries here-
Since in Implicit flow a refresh token is not issued, does it means that th user will be logged out of the app after the token expires and he has to log in again?
Why do I need to use Implicit flow in case of SPA? why not Authorization code flow? since I have control over both the front end (SPA) and back end (REST API) . for example in case of Spring MVC architecture for the web app Authorization code flow is possible.
Thanks,
pchh
Yes, if the token expired, you have to re-autenticate. Normally you still have a valid session on the identity providers site, so you can do a "silent" login using an iframe. Libraries like oidc-client support a silent login, which can do this for you.
You need to use implicit (or hybrid) flow, when you need to access to the access token from your javascript app. With authorization code flow your javascript app doesn't get the access token, so if your API needs an access token for authorization, what are you going to send?
If your auth server supports OpenID Connect (OAuth2 extension) and single sign-on (SSO) feature, to get a new token before the old gets expired, use an iframe with a URL you used for authentication, but add prompt=none parameter (and possibly id_token_hint parameter). See OpenId Connect RFC. The prompt=none parameter tells the /auth endpoint to issue a new token(s) if the user has an open SSO session at your OAuth2 server. If not, the request will fail. There is a separate RFC for session management.
The Authorization code flow requires you to access the /token endpoint, which usually requires authentication (client ID + client secret) and you cannot keep the secret safe in a browser. For this reason, the token endpoint doesn't use to support CORS headers, so you cannot access it using XHR. Using the Auth code flow, you get a code as a redirect URL param (?code=), which gets to the server hosting your SPA (browser sends it there after redirect). The implicit flow returns tokens in hash part of the redirect URL (#access_token=), which stays in a browser (it's not sent to the server), so it's safer.
Here is my plan (authorization code flow) of implementing such login/register logic. (The third-party only provided the OAuth2 API)
First the SPA frontend will send a GET request to the third-party
GET https://www.example.com/oauth2
client_id=dummyclient
redirect_uri=https://mysite/callback
response_type=code
scope=openid
Then if the user agree to give his/her openid to mysite then the fronend will get a 301 HTTP response.
---> 301 https://mysite/callback?code=dummycode
Then the browser will redirect the page to mysite/callback and it will reload SPA and expose the code in URL which can be captured by the SPA then it will send the code to the real backend callback.
GET https://mysite/api/real-callback?code=dummycode
When the backend get the code, it will send the code to the third-party to exchange an access_token. When the backend get the access_token, it will fire an API request to get the user's openid then decide whether to let the user login or register as a new user. At last it will give back a HTTP response to our SPA frontend which contains the access_token in my OAuth2 system or a 401 unauthorized response.
So my question is how to prove that the real callback is invoked by my own clients (Because if some attacker get my frontend embedded client_id then he can fake the OAuth2 request and phishing the user to agree. After that the attacker will get a valid code then he send back the code to my real callback. Finally, he will get the user's access_token in my system.) How can I use OAuth2 to do authentication without the end user's providing additional information like password.
I would suggest you to change the OAuth2 flow to Implicit and ask for both access_token and id_token (OpenID Connect). Your SPA will get the tokens, send the ID token to your backend, which can use it to decide whether it's possible to create such user. The SPA can use the access token to call protected resources.
This way,
only the SPA will be an OAuth2 client - tokens will not be used by two applications (SPA and backend),
you will have just one redirect URI,
you will not need to transfer tokens from the backend to the SPA.
Update: Without OpenID Connect
If you cannot use the id_token, you could send the access_token to your backend and the backend can get the user's username by sending to token to the Introspection endpoint https://www.rfc-editor.org/rfc/rfc7662 (from the response username attribute). The username attribute is optional. Your OAuth2 server may return even more info (such as name and email).
This Introspection endpoint requires authentication, so to use it, your backend will have to be a registered OAuth2 client with its own client_id and a secret.
I am implementing DocuSign's OAuth flow by following OAuth2 Authentication Support in DocuSign REST API
According to the documentation, in order to carry out the OAuth Token Request the client application should show a UI to prompt the user for email/password and is responsible to keep the information confidential and not store it locally.
I would like to know if DocuSign supports OAuth in the manner where the client application does not take hold of the user's email and password and is just concerned with the authentication token of the user.
The DocuSign Developer Center has some info on the OAuth process on their SOBO (Send-On-Behalf-Of) feature page. Check out Explore -> Features -> SOBO.
It's pretty easy to request an access token, just make the following call:
URL
https://{server}/restapi/{apiVersion}/oauth2/token
METHOD
POST
BODY
grant_type=password&client_id={IntegratorKey}&username={email}&password={password}&scope=api
For the body make sure you replace IntegratorKey, email, and password with your credentials.
A successful call will generate the following response:
{
"access_token": "<access token for user>",
"scope": "api",
"token_type": "bearer"
}
And finally, you can then use that access token in subsequent api calls using the Authorization: bearer header like so:
Authorization: bearer <access_token>
One important thing to remember is that you are only allowed 10 OAuth tokens in your account (which can be seen on the Preferences -> Connected Apps screen in the DocuSign Console). If you have 10 and request a new token the call will fail, you'll need to revoke an existing one in that case if you want to create a new one.
According to the DocuSign documentation, it supports two grants: (1) the Resource Owner Password Credentials Grant and (1) the SAML2 Grant, which is an extension to the base OAuth2 spec. Neither of these grants issue an authentication token. In the first grant, the resource owner must share his credentials with the client application. In the second grant, the resource owner approves access by the client application in advance. The client app generates a SAML assertion which is validated by the authorization server and (if the assertion is valid) is issued an access token.
The authentication token is used only by the Authentication Code Grant which, according to the DocuSign documentation, is not supported.
I am following this tutorial about OAuth2.0 https://developers.google.com/youtube/v3/guides/authentication
It looks quite clear how OAuth2.0 works. But I have a bit confusion at the access token part.
After obtaining an access token for a user, your application can use
that token to submit authorized API requests on that user's behalf.
The API supports two ways to specify an access token: Specify the
access token as the value of the access_token query parameter:
www.googleapis.com/youtube/v3/videos?access_token=ACCESS_TOKEN
if someone acquired this access token during the url transferring they can access this protected resource right?
How the server know if the request is coming from the client initially requested the access token?
UPDATE:
after reading this post Are HTTPS headers encrypted? my confusion is cleared. I thought query string is not encrypted during transmission in the network.
Generally I think the consensus is that OAuth 2.0 is a server side technology and all access tokens and communication should be transmitted using SSL as the bearer tokens need to be kept as secure as possible.
Also, you need to know that there are 2 types of flows in OAuth 2.0
i) Implicit grant flow - This is the flow where the user logs in to the service provider and his browser gets the access token. Say you have X.com and Log in via Facebook. Once the user keys in his FB credentials, the access token is sent to his browser.
ii) Authorization Code flow - In this flow (consider the above situation again), facebook will pass an authorization code to the user's browser. If anyone, somehow, intercepts the authorization code there is nothing he can do. An authorization code can be exchanged for an access when passed with valid client credentials. So, when the user logs in, his browser gets an authorization code which is passed to your server at X.com. from there you would hit the code-token exchange endpoint provided by FB and get the access token returned to your server!
Authorization code flow adds another layer of security, where the access token is visible only to the client + server and not to the user agent. And as you figured out yourself, the token is passed via HTTPS.
We want to set up our own OAuth 2.0 authorization server based on the following roles:
Resource Server - An API built with ASP.NET Web API
Client - A web application built with ASP.NET MVC
Resource Owner - The end user
We plan to use the password grant type (Resource Owner Password Credentials Grant) such that the Resource Owner will submit their credentials to the Client, who will in turn make an Authorization Request. We want to authenticate the Client Request with Basic Authentication.
I'm struggling with how to set up an Authorization server using DNOA that supports this grant type. I've downloaded the Authorization Server sample project but this appears to be using token based grants (user authenticates directly with authorization server - in the sample, via OpenID).
When I try and make an Authorization request using fiddler I'm just redirected to the login page, so I'm assuming this sample doesn't support this grant type:
POST http://localhost:50172/oauth/authorize HTTP/1.1
User-Agent: Fiddler
Host: localhost:50172
Content-Length: 103
grant_type=password&client_id=sampleconsumer&client_secret=samplesecret&username=user&password=password
The same is true if I use basic authentication.
Any help would be appreciated. I've used DNOA with great success in the past to consume OAuth services, but am finding the documentation on setting up/configuring a server pretty sparse.
It looks like you are sending the password grant to the authorization server's authorization endpoint which is wrong. Grants should go directly to the token endpoint, which must be at a URL that the authorization server does not require an authenticated request to access (i.e. won't cause ASP.NET to redirect to the login page).
That said, it's very unusual (and discouraged) for a web based client app to ask the user for a password to another web service. The authorization code flow is by far the preferred one for the scenario you sound like you're describing.