As I said in the previous blog about OIDC, OIDC is running on top of OAuth in-order to provide authentication and authorization. When it comes to real scenario, we have need to clearly understand the flows between authorization server, and resource server. For OAuth it needs token introspection endpoint in-order to validate the token. But, in OIDC it doesn't need to have this introspection endpoint because OIDC response token (JWT) it contains the idtoken which contains information about the token to validate by the resource server. OIDC is running as authorization grant type is pretty much safe way for the web applications.
Let's see how a real world application using this OIDC on top of OAuth.
Note: I have created an sample application to provide the graphical interface for this explanation.
- When you are trying to login a online web application account you may see another login options also available. For example, login with Google, login with Facebook,etc. Those things are running on OAuth + OIDC to log into the applications. [Google, Facebook, also providing these kind of OAuth services to share it's user's information. Here, I am using Auth0 to login without creating a account/login via username and password]
- As usual in OAuth, the authorization server response with the user consent page on the redirection URL to the client application (your created application), in-order to get the permission from the user (what claims the 3rd party clients can borrow from the resource server (here resources are stored in identity server which is acting as authorization server and resource server).
- After the user permission client app will receive the OIDC token, which no need further validation (token introspection). Because all the information are stored in the idtoken (you wont see the flow in the URL because in my case I gave the flows in POST services). Finally client application will successfully get the required information.
[Here I have logged Auth0 by using my gmail, so it's get my profile picture and other details through Google, now it sharing the information what is it having to the OIDC(my created application) client application]
Let's see the things with the rest-client and with the source codes (I have wrote those flows in each function in AppRestController.java).
Protocols endpoints:
Authorization endpoint: https://benjamine.auth0.com/authorize
Token endpoint: https://benjamine.auth0.com/oauth/token
Client registration:
[This is on my previous blog]
Client_ID: 1BgekLBANaKy6r076OCdMZ0zzonrpcWc
Client_Secret: Bra4e8ICHwkAdT5LjezJIil573E6gJY3xf7EJyJ7L6oPI1n7f7MACZjR8T7g0jYN
Authorization code grant type:
In-order to get the authorization code the request URL will be like this.
Request:
This will redirects you to get the users permission and the response with the code.
Response:
Function written to get the authorization code:
[This function needs to execute when we click the login with Auth0]
Request Access token by using the authorization code:
This will be a POST request contains 2 headers.
Headers:
Authorization: Basic<client_ID:client_secret> -->[no need if you add them inside the body]
Example:
content-type: application/x-www-form-urlencoded
Request URL: [Token endpoint]
https://benjamine.auth0.com/oauth/token
POST body:
Response:
Access token(JWT)
Function written to get the access token:
Extract the data from the access token: [By using JWT decorders]
Copy the id_token data and decode it by using JWT decorders [https://jwt.io/]
Extract the data from the access token: [By using functions]
My next blog will contain how to validate the JWT signature.
Let's see the things with the rest-client and with the source codes (I have wrote those flows in each function in AppRestController.java).
Protocols endpoints:
Authorization endpoint: https://benjamine.auth0.com/authorize
Token endpoint: https://benjamine.auth0.com/oauth/token
Client registration:
[This is on my previous blog]
Client_ID: 1BgekLBANaKy6r076OCdMZ0zzonrpcWc
Client_Secret: Bra4e8ICHwkAdT5LjezJIil573E6gJY3xf7EJyJ7L6oPI1n7f7MACZjR8T7g0jYN
Authorization code grant type:
In-order to get the authorization code the request URL will be like this.
Request:
https://benjamine.auth0.com/authorize?audience=https://benjamine.auth0.com/api/v2/&scope=openid%20profile&response_type=code&client_id=1BgekLBANaKy6r076OCdMZ0zzonrpcWc&redirect_uri=http%3A%2F%2Flocalhost%3A9090%2Foidcapp%2Fcallback&state=123
This will redirects you to get the users permission and the response with the code.
Response:
http://localhost:9090/oidcapp/callback?code=R3bnvlibRaQ4rZRP&state=123
Function written to get the authorization code:
@RequestMapping(value = "/login-auth0", method=RequestMethod.GET) public RedirectView processForm1() { RedirectView redirectView = new RedirectView(); //Prepare the OAuth Authorization URL String url = "https://benjamine.auth0.com/authorize?"+ "audience=https://benjamine.auth0.com/api/v2/"+ "&scope=openid%20profile"+ "&response_type=code"+ "&client_id=1BgekLBANaKy6r076OCdMZ0zzonrpcWc"+ "&redirect_uri=http%3A%2F%2Flocalhost%3A9090%2Foidcapp%2Fcallback"+ "&state=123"; redirectView.setUrl(url); return redirectView; }
[This function needs to execute when we click the login with Auth0]
Request Access token by using the authorization code:
This will be a POST request contains 2 headers.
Headers:
Authorization: Basic<client_ID:client_secret> -->[no need if you add them inside the body]
Example:
BasicMUJnZWtMQkFOYUt5NnIwNzZPQ2RNWjB6em9ucnBjV2M6QnJhNGU4SUNId2tBZFQ1TGplekpJaWw1NzNFNmdKWTN4ZjdFSnlKN0w2b1BJMW43ZjdNQUNaalI4VDdnMGpZTg==[client_ID:client_Secret needs to be base64 encode]
content-type: application/x-www-form-urlencoded
Request URL: [Token endpoint]
https://benjamine.auth0.com/oauth/token
POST body:
grant_type=authorization_code&client_id=1BgekLBANaKy6r076OCdMZ0zzonrpcWc&client_secret=Bra4e8ICHwkAdT5LjezJIil573E6gJY3xf7EJyJ7L6oPI1n7f7MACZjR8T7g0jYN&code=bR-Xb6-GQl90s-E1&redirect_uri=http%3A%2F%2Flocalhost%3A9090%2Foidcapp%2Fcallback
Response:
Access token(JWT)
{"access_token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6Ik1VUXlPVUkxTlVFM09FUkVOalEwTVVVMk9USTVNVVpCTkRBd1JVTXlRekZFTnpRM09UZ3hSUSJ9.eyJpc3MiOiJodHRwczovL2JlbmphbWluZS5hdXRoMC5jb20vIiwic3ViIjoiYXV0aDB8NWJkNTIyN2EzZjMyNWYwZDhmODExNTYxIiwiYXVkIjpbImh0dHBzOi8vYmVuamFtaW5lLmF1dGgwLmNvbS9hcGkvdjIvIiwiaHR0cHM6Ly9iZW5qYW1pbmUuYXV0aDAuY29tL3VzZXJpbmZvIl0sImlhdCI6MTU0MDY5ODEwMSwiZXhwIjoxNTQwNjk4NDYxLCJhenAiOiIxQmdla0xCQU5hS3k2cjA3Nk9DZE1aMHp6b25ycGNXYyIsInNjb3BlIjoib3BlbmlkIHByb2ZpbGUifQ.jjOQHLHiWEscfCHU7XSVo1PFdFHKY98RG2B6BJrej3OKnzVqlScRjxPg9Y2Wb4F_rzHkmgWym0DCVk6Mlv2wBmBHJBoLDUqwVYugQ21I4ayJgbd-y8asrwTiwriBFGCPeae_GOu4uQaEUfRk8pxM-PVDJ_GZeM7iL-6E4OTPPallj3egAt49wIoaJE-yxggG5P01DGAIs1L3UkUImbmq8I1ojG1EnEk_XLm3mqEAZhR57sfIpLC893a4p6r5OSGftMuFWdWjSwPXo4eNUt9VRTTpZ_If8NZ9vHigxrWiKppL8Hbj1pDwgk6xpv-Wg68lplMgNfNaAG91EN6ncmWVqA","id_token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6Ik1VUXlPVUkxTlVFM09FUkVOalEwTVVVMk9USTVNVVpCTkRBd1JVTXlRekZFTnpRM09UZ3hSUSJ9.eyJuaWNrbmFtZSI6InNhaGF5YW5hdGhhbmJlbmphbWluZS5zYiIsIm5hbWUiOiJzYWhheWFuYXRoYW5iZW5qYW1pbmUuc2JAZ21haWwuY29tIiwicGljdHVyZSI6Imh0dHBzOi8vcy5ncmF2YXRhci5jb20vYXZhdGFyL2M4NzhlNTkyNzY3Zjk4YTczNzA0ZTViNjYwMTIyZGZkP3M9NDgwJnI9cGcmZD1odHRwcyUzQSUyRiUyRmNkbi5hdXRoMC5jb20lMkZhdmF0YXJzJTJGc2EucG5nIiwidXBkYXRlZF9hdCI6IjIwMTgtMTAtMjhUMDM6MDQ6MDEuOTc1WiIsImlzcyI6Imh0dHBzOi8vYmVuamFtaW5lLmF1dGgwLmNvbS8iLCJzdWIiOiJhdXRoMHw1YmQ1MjI3YTNmMzI1ZjBkOGY4MTE1NjEiLCJhdWQiOiIxQmdla0xCQU5hS3k2cjA3Nk9DZE1aMHp6b25ycGNXYyIsImlhdCI6MTU0MDY5ODEwMSwiZXhwIjoxNTQwNjk4NDYxfQ.jZbPgxo8LeRXHW60UfOObpr-8xHRaDQWa3ubZmsvgAtNkcuvhKyI52cjajlZC98aAKeIMifhu4RNjPLGocQMyLk9c8mIrKqLGpIf_hb2Srai0uBs41mH4Ok-Xdq4C0CToAfAm7dyS6uCbe5cgKcDHaPJOMpGD98XodLFSWaBZasw3ymBF95om0x1i7F_orsV0bCKPxHjBJ7fgXmy1XrBsAPLOIK4Hz_M1DyXeWbedyhOH7akMBlu3bphUrAZlYRuGvGBzoNeifLvz80W-DO_GVH-qSWmwxwclWJ9mKtIkjQjL7vqyGVclOXy78Nb3PudTKWeZdlBO6DissCmDAahbQ","scope":"openid profile","expires_in":360,"token_type":"Bearer"}
Function written to get the access token:
public String getAuthResponse(String authCode) { ////Prepare the POST request to get the access_token and id_token //OAuth Token URL String auth_url = "https://benjamine.auth0.com/oauth/token"; //Prepare POST Request Body String POST_PARAMS = "grant_type=authorization_code"+ "&client_id=1BgekLBANaKy6r076OCdMZ0zzonrpcWc"+ "&client_secret=Bra4e8ICHwkAdT5LjezJIil573E6gJY3xf7EJyJ7L6oPI1n7f7MACZjR8T7g0jYN"+ "&code="+authCode+ "&redirect_uri=http%3A%2F%2Flocalhost%3A9090%2Foidcapp%2Fcallback"; String authReponse = ""; try { //Create the objects of URL and the HttpURLConnection and set the request method to POST URL obj = new URL(auth_url); HttpURLConnection con = (HttpURLConnection) obj.openConnection(); con.setRequestMethod("POST"); //Set Headers con.setRequestProperty("content-type", "application/x-www-form-urlencoded"); //Set Body con.setDoOutput(true); OutputStream os = con.getOutputStream(); os.write(POST_PARAMS.getBytes()); os.flush(); os.close(); //Execute and get the response int responseCode = con.getResponseCode(); if (responseCode == HttpURLConnection.HTTP_OK)//success { BufferedReader in = new BufferedReader(new InputStreamReader( con.getInputStream())); String inputLine; StringBuffer response = new StringBuffer(); while ((inputLine = in.readLine()) != null) { response.append(inputLine); } in.close(); authReponse = response.toString(); } else { System.out.println("Error : " + responseCode); } } catch (Exception ex) { System.out.println(ex); } //Return the response received return authReponse; }
Extract the data from the access token: [By using JWT decorders]
Copy the id_token data and decode it by using JWT decorders [https://jwt.io/]
Extract the data from the access token: [By using functions]
@RequestMapping(value = "/oidcapp/callback", method = RequestMethod.GET) public RedirectView authUser(ModelMap model, @RequestParam(value = "code",required=true) String authCode) { try{ //Get the access token and id_token from the auth0 server by providing the code received String response = getAuthResponse(authCode); //return response; //Extract the user data from the received response //return getUserData(response); --> old JSONObject jsonBody = getUserData(response); this.nickname = jsonBody.getString("nickname"); this.picture = jsonBody.getString("picture"); this.JASON_RESPONSE=jsonBody.toString(); //Set the attribute to the page and redirect the user to the user's home page return viewHomePage(); } catch(Exception ex){ System.out.println(ex); } return null; } public RedirectView viewHomePage(){ AppController app = new AppController(); app.setModelAttribute("nickname",this.nickname); app.setModelAttribute("picture",this.picture); app.setModelAttribute("JASON_RESPONSE", this.JASON_RESPONSE); app.setModelAttribute("verify_status",this.msgVerify); RedirectView redirectView = new RedirectView(); redirectView.setUrl("/home"); return redirectView; }
My next blog will contain how to validate the JWT signature.
Comments
Post a Comment