<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Shyamala</title>
    <description>The latest articles on Forem by Shyamala (@shyamala_u).</description>
    <link>https://forem.com/shyamala_u</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F10403%2F5d0c7410-ad7c-4dbf-bf7d-48b8dc815b5a.jpg</url>
      <title>Forem: Shyamala</title>
      <link>https://forem.com/shyamala_u</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/shyamala_u"/>
    <language>en</language>
    <item>
      <title>The case of disappearing metrics in Kubernetes</title>
      <dc:creator>Shyamala</dc:creator>
      <pubDate>Sun, 24 May 2020 15:46:30 +0000</pubDate>
      <link>https://forem.com/shyamala_u/the-case-of-disappearing-metrics-in-kubernetes-1kdh</link>
      <guid>https://forem.com/shyamala_u/the-case-of-disappearing-metrics-in-kubernetes-1kdh</guid>
      <description>&lt;h2&gt;
  
  
  🧐 Context 🧐
&lt;/h2&gt;

&lt;p&gt;My team hosts the kubernetes platform running on &lt;a href="https://aws.amazon.com/eks/"&gt;EKS&lt;/a&gt; for several teams. When EKS announced the support for Kubernetes version 1.16 we upgraded our infrastructure. This is pretty routine process for us. We use Prometheus and grafana dashboard to observe and monitor our infrastructure. &lt;/p&gt;

&lt;p&gt;After we upgraded, our metrics dashboard stopped showing RAM and CPU utilization of pods. I set out to find why?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/42wQXwITfQbDGKqUP7/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/42wQXwITfQbDGKqUP7/giphy.gif" alt="detective"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  ⚠️ Disclaimer ⚠️
&lt;/h2&gt;

&lt;p&gt;Before we move ahead, &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I am a newbie to Kubernetes learning the tricks on the job&lt;/li&gt;
&lt;li&gt;This is my journey on how I debugged the issue, so what is obvious to a Kubernetes expert is not obvious to me.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  TL;DR
&lt;/h3&gt;

&lt;p&gt;If you already know what caused this issue, jump to final section&lt;/p&gt;

&lt;h2&gt;
  
  
  Debugging Step 1:
&lt;/h2&gt;

&lt;p&gt;So the dashboard is not showing metrics, normally Kubectl has commands that shows the CPU and RAM utilization of the Nodes and Pods. So I checked if those worked.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; kubectl top nodes
NAME                                         CPU&lt;span class="o"&gt;(&lt;/span&gt;cores&lt;span class="o"&gt;)&lt;/span&gt;   CPU%   MEMORY&lt;span class="o"&gt;(&lt;/span&gt;bytes&lt;span class="o"&gt;)&lt;/span&gt;   MEMORY%
ip-xx-xx-xxx-xxx.ec2.internal   8xxm         5%     2xxxxMi         23%
ip-xx-xx-xxx-xxx.ec2.internal   2xxxxm       15%    3xxxxMi         29%
ip-....

&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; kubectl top pods
NAME         CPU&lt;span class="o"&gt;(&lt;/span&gt;cores&lt;span class="o"&gt;)&lt;/span&gt;   MEMORY&lt;span class="o"&gt;(&lt;/span&gt;bytes&lt;span class="o"&gt;)&lt;/span&gt;
xxxx-wnpgj   xxm          xxMi
xxxx-r4k85   xxm          xxxMi
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  🤔 What does this mean? 🤔
&lt;/h3&gt;

&lt;p&gt;Kubernetes is able to fetch the metrics. These are the metrics that have to be used by the &lt;a href="https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/#how-does-the-horizontal-pod-autoscaler-work"&gt;HPA&lt;/a&gt; to scale the Pods based on the resource utilization. &lt;/p&gt;
&lt;h2&gt;
  
  
  Debugging Step 2:
&lt;/h2&gt;

&lt;p&gt;Since the dashboard does not show the resource utilization metrics, but the &lt;code&gt;kubectl top&lt;/code&gt; command works, my next thought was may be the &lt;code&gt;scaling does not work properly anymore&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;According to &lt;a href="https://kubernetes.io/docs/tasks/debug-application-cluster/resource-usage-monitoring/#resource-metrics-pipeline"&gt;Resource usage monitoring&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;components such as the Horizontal Pod Autoscaler controller, as well as the kubectl top utility. These metrics are collected by the lightweight, short-term, in-memory metrics-server and are exposed via the metrics.k8s.io API&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So now I wanted to see what is the status with one of our teams.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; kubectl get hpa &lt;span class="nt"&gt;-n&lt;/span&gt; xxx 
NAME         REFERENCE               TARGETS           MINPODS   MAXPODS   REPLICAS   AGE
xxx-worker   Deployment/xxx-worker   82/150, 5%/100%   1         6         1          4d19h
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Since the Targets look fine in the above output. I thought let me see if at any point the scaling actually happened.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; kubectl describe hpa &lt;span class="nt"&gt;-n&lt;/span&gt; xxx 

Type     Reason                   Age                      From                       Message
&lt;span class="nt"&gt;----&lt;/span&gt;     &lt;span class="nt"&gt;------&lt;/span&gt;                   &lt;span class="nt"&gt;----&lt;/span&gt;                     &lt;span class="nt"&gt;----&lt;/span&gt;                       &lt;span class="nt"&gt;-------&lt;/span&gt;
Warning  FailedGetResourceMetric  25m &lt;span class="o"&gt;(&lt;/span&gt;x24 over 2d23h&lt;span class="o"&gt;)&lt;/span&gt;     horizontal-pod-autoscaler  unable to get metrics &lt;span class="k"&gt;for &lt;/span&gt;resource cpu: no metrics returned from resource metrics API
Normal   SuccessfulRescale        9m56s &lt;span class="o"&gt;(&lt;/span&gt;x233 over 2d23h&lt;span class="o"&gt;)&lt;/span&gt;  horizontal-pod-autoscaler  New size: 2&lt;span class="p"&gt;;&lt;/span&gt; reason: cpu resource utilization &lt;span class="o"&gt;(&lt;/span&gt;percentage of request&lt;span class="o"&gt;)&lt;/span&gt; above target
Normal   SuccessfulRescale        4m9s &lt;span class="o"&gt;(&lt;/span&gt;x233 over 2d22h&lt;span class="o"&gt;)&lt;/span&gt;   horizontal-pod-autoscaler  New size: 1&lt;span class="p"&gt;;&lt;/span&gt; reason: All metrics below target
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  🤔 What does this mean? 🤔
&lt;/h3&gt;

&lt;p&gt;As we can see at some point fetching the resource metric failed but we can also see that the system recovered and was able to scale successfully. &lt;/p&gt;

&lt;p&gt;Since there is a &lt;code&gt;FailedGetResourceMetric&lt;/code&gt; at some point, I thought this could lead me to why metrics do not appear in the dashboard.&lt;/p&gt;
&lt;h2&gt;
  
  
  Debugging Step 3:
&lt;/h2&gt;

&lt;p&gt;As we have seen from several documentation mentioned above and also from the error &lt;code&gt;no metrics returned from resource metrics API&lt;/code&gt;. There is some component in Kubernetes that is responsible for the metrics. So I cast a wide net&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; kubectl get all &lt;span class="nt"&gt;-n&lt;/span&gt; metrics | &lt;span class="nb"&gt;grep &lt;/span&gt;metrics | &lt;span class="nb"&gt;grep &lt;/span&gt;pod
pod/metrics-server-xxxxxxx-xxxxx                        1/1     Running            0          4d21h
pod/prometheus-kube-state-metrics-xxxx-xxxxx            1/1     Running            0          4d21h
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;This sound promising. So &lt;code&gt;metrics-server&lt;/code&gt; sounds like some server dealing with metrics. Naturally I am interested in logs&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; k logs &lt;span class="nt"&gt;-n&lt;/span&gt; metrics pod/metrics-server-xxxxxxx-xxxxx
I0524 11:17:54.371856       1 manager.go:120] Querying &lt;span class="nb"&gt;source&lt;/span&gt;: kubelet_summary:ip-xx-xx-xxx-xxx.ec2.internal
I0524 11:17:54.388840       1 manager.go:120] Querying &lt;span class="nb"&gt;source&lt;/span&gt;: kubelet_summary:ip-xx-xx-xxx-xxx.ec2.internal
I0524 11:17:54.495829       1 manager.go:148] ScrapeMetrics: &lt;span class="nb"&gt;time&lt;/span&gt;: 233.232388ms, nodes: x, pods: xxx
E0524 11:18:18.542051       1 reststorage.go:160] unable to fetch pod metrics &lt;span class="k"&gt;for &lt;/span&gt;pod my-namespace/team-worker-xxxxx-xxxx: no metrics known &lt;span class="k"&gt;for &lt;/span&gt;pod
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  🤔 What does this mean? 🤔
&lt;/h3&gt;

&lt;p&gt;As soon as I saw the words &lt;code&gt;ScrapeMetrics&lt;/code&gt; (my brain translated it to Prometheus related) and the error &lt;code&gt;unable to fetch pod metrics for pod my-namespace/team-worker-xxxxx-xxxx: no metrics known for pod&lt;/code&gt;&lt;br&gt;
I thought I have found the issue.&lt;/p&gt;
&lt;h2&gt;
  
  
  Debugging Step 4:
&lt;/h2&gt;

&lt;p&gt;As any seasoned developer would do, I took the error message and googled it. Which resulted in some links and on a quick scan, I found couple of interesting Links &lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--QAQCHiO6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/n0stnswd90ro145nvx0a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QAQCHiO6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/n0stnswd90ro145nvx0a.png" alt="Links from google search"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After quickly scanning through the links, every one seem to suggest this following change in metrics-server&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/metrics-server&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--kubelet-insecure-tls&lt;/span&gt; &lt;span class="c1"&gt;#&amp;lt;-- 🤓&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;--kubelet-preferred-address-types=InternalIP&lt;/span&gt; &lt;span class="c1"&gt;#&amp;lt;-- 🤓&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;&lt;code&gt;--kubelet-insecure-tls&lt;/code&gt; seems like something you would do in a test setup. So I wanted to understand a bit more what this flags do.&lt;br&gt;
From the &lt;a href="https://github.com/kubernetes-sigs/metrics-server#configuration"&gt;documentation&lt;/a&gt;, it is clear that the above flag is intended for testing purposes only and in the logs of metrics server I did not find any error pertaining to certificates. So I did not add the flag.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;--kubelet-preferred-address-types&lt;/code&gt; this configuration is to determine which address type to use to connect to the nodes for getting the metrics. &lt;br&gt;
So before adding this config I wanted to verify if the metrics server api was reachable or not.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; kubectl get apiservices | &lt;span class="nb"&gt;grep &lt;/span&gt;metrics-server
v1beta1.metrics.k8s.io                 kube-system/metrics-server       True        4d23h
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;since the status of this service is available, those two flags would not make any sense. I wanted to see if I can get some raw metrics by querying this API.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; kubectl get &lt;span class="nt"&gt;--raw&lt;/span&gt; &lt;span class="s2"&gt;"/apis/metrics.k8s.io/v1beta1/pods"&lt;/span&gt; | jq &lt;span class="s1"&gt;'.items | .[] | select(.metadata.namespace == "xxx")'&lt;/span&gt;
&lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="s2"&gt;"metadata"&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="s2"&gt;"name"&lt;/span&gt;: &lt;span class="s2"&gt;"xxx-worker-6c5bd59857-xxxxx"&lt;/span&gt;,
    &lt;span class="s2"&gt;"namespace"&lt;/span&gt;: &lt;span class="s2"&gt;"xxx"&lt;/span&gt;,
    &lt;span class="s2"&gt;"selfLink"&lt;/span&gt;: &lt;span class="s2"&gt;"/apis/metrics.k8s.io/v1beta1/namespaces/xxx/pods/xxx-worker-6c5bd59857-xxxxx"&lt;/span&gt;,
    &lt;span class="s2"&gt;"creationTimestamp"&lt;/span&gt;: &lt;span class="s2"&gt;"2020-05-24T12:06:45Z"&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;,
  &lt;span class="s2"&gt;"timestamp"&lt;/span&gt;: &lt;span class="s2"&gt;"2020-05-24T12:05:48Z"&lt;/span&gt;,
  &lt;span class="s2"&gt;"window"&lt;/span&gt;: &lt;span class="s2"&gt;"30s"&lt;/span&gt;,
  &lt;span class="s2"&gt;"containers"&lt;/span&gt;: &lt;span class="o"&gt;[&lt;/span&gt;
    &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="s2"&gt;"name"&lt;/span&gt;: &lt;span class="s2"&gt;"xxx-worker"&lt;/span&gt;,
      &lt;span class="s2"&gt;"usage"&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="s2"&gt;"cpu"&lt;/span&gt;: &lt;span class="s2"&gt;"xxxxxn"&lt;/span&gt;,
        &lt;span class="s2"&gt;"memory"&lt;/span&gt;: &lt;span class="s2"&gt;"xxxxxxxKi"&lt;/span&gt;
      &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
  &lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  🤔 What does this mean? 🤔
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/ql4LidslabKpi/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/ql4LidslabKpi/giphy.gif" alt="Frustration"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So everything seems to function well. I do not know why the metrics I am clearly able to query via &lt;code&gt;Kubectl&lt;/code&gt; is not available for the dashboard.&lt;/p&gt;
&lt;h2&gt;
  
  
  Debugging Step 5:
&lt;/h2&gt;

&lt;p&gt;Now I want to see the source code of &lt;a href="https://github.com/kubernetes-sigs/metrics-server/blob/d1f4f6fc09cd3134e8ea5ba4e0bd2db4e8002ed8/pkg/storage/podmetrics/reststorage.go#L133"&gt;metrics-server&lt;/a&gt; to figure out under what circumstance this error happens&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight go"&gt;&lt;code&gt;    &lt;span class="n"&gt;podMetrics&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getPodMetrics&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pod&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;podMetrics&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"no metrics known for pod &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;%s/%s&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pod&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Namespace&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pod&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;klog&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"unable to fetch pod metrics for pod %s/%s: %v"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pod&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Namespace&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pod&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewNotFound&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;groupResource&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"%v/%v"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;namespace&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;It is very clear from the code that the Pod exists but metrics is not available. So I tailed the logs and got the pod for which metrics is not found&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; kubectl get po &lt;span class="nt"&gt;-n&lt;/span&gt; xxx
NAME                          READY   STATUS    RESTARTS   AGE
xxx-worker-6c5bd59857-xxxxx   1/1     Running   0          1m5s
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  🤔 What does this mean? 🤔
&lt;/h3&gt;

&lt;p&gt;It is very clear from above that all these pods where metrics are not available are pods that have been recently created &lt;br&gt;
and since metrics server scrapes for metrics periodically, it's just not available at the moment.&lt;/p&gt;

&lt;p&gt;In my opinion it is really not an &lt;code&gt;ERROR&lt;/code&gt; rather an expected behaviour. A &lt;code&gt;WARN&lt;/code&gt; or &lt;code&gt;INFO&lt;/code&gt; would be reasonable. It is good to see am not alone in this&lt;/p&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/kubernetes-sigs/metrics-server/issues/349"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://res.cloudinary.com/practicaldev/image/fetch/s--vWogaON8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/github-logo-28d89282e0daa1e2496205e2f218a44c755b0dd6536bbadf5ed5a44a7ca54716.svg"&gt;
      &lt;span class="issue-title"&gt;
        Remove/propose different "no metrics known for pod" log
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#349&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/serathius"&gt;
        &lt;img class="github-liquid-tag-img" src="https://res.cloudinary.com/practicaldev/image/fetch/s--snv7FVcT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://avatars2.githubusercontent.com/u/5873433%3Fv%3D4" alt="serathius avatar"&gt;
      &lt;/a&gt;
      &lt;span class="arrow-left-outer"&gt;&lt;/span&gt;
      &lt;span class="arrow-left-inner"&gt;&lt;/span&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/serathius"&gt;serathius&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/kubernetes-sigs/metrics-server/issues/349"&gt;&lt;time&gt;Nov 05, 2019&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;p&gt;There are a lot of issues where users are seeing metrics-server reporting error "no metrics known for pod" and asking for help.&lt;/p&gt;
&lt;p&gt;To my understanding this error is expected to occur in normal healthy metrics-server.
Metrics Server periodically scrapes all nodes to gather metrics and populate it's internal cache. When there is a request to Metrics API, metrics-server reaches to this cache and looks for existing value for pod. If there is no value for existing pod in k8s, metrics server reports error "no metrics known for pod". This means this error can happen in situation when:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;fresh metrics-server is deployed with clean cache&lt;/li&gt;
&lt;li&gt;query is about fresh pod/node that was not yet scraped&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Providing better information to users would greatly reduce throughput of tickets.&lt;/p&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/kubernetes-sigs/metrics-server/issues/349"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;I have been chasing a wrong lead after all.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--l0W-_Spg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgflip.com/42nax3.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--l0W-_Spg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgflip.com/42nax3.jpg" alt="back to square one"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Debugging Step 5:
&lt;/h2&gt;

&lt;p&gt;I have eliminated that Metrics server is not the reason for the bug. This got me to thinking, I should find how Prometheus is scraping the metrics.&lt;/p&gt;

&lt;p&gt;After a lot of reading I figured out Prometheus gets the metrics exposed by the &lt;code&gt;kube-state-metrics&lt;/code&gt;. It is very important to understand the difference between &lt;code&gt;metrics-server&lt;/code&gt; and &lt;code&gt;kube-state-metrics&lt;/code&gt;&lt;/p&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/kubernetes-sigs/metrics-server/issues/55#issuecomment-387229420"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://res.cloudinary.com/practicaldev/image/fetch/s--vWogaON8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/github-logo-28d89282e0daa1e2496205e2f218a44c755b0dd6536bbadf5ed5a44a7ca54716.svg"&gt;
      &lt;span class="issue-title"&gt;
        Comment for
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#55&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/metalmatze"&gt;
        &lt;img class="github-liquid-tag-img" src="https://res.cloudinary.com/practicaldev/image/fetch/s--x9IZiTq1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://avatars1.githubusercontent.com/u/872251%3Fv%3D4" alt="metalmatze avatar"&gt;
      &lt;/a&gt;
      &lt;span class="arrow-left-outer"&gt;&lt;/span&gt;
      &lt;span class="arrow-left-inner"&gt;&lt;/span&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/metalmatze"&gt;metalmatze&lt;/a&gt;
        &lt;/strong&gt; commented on &lt;a href="https://github.com/kubernetes-sigs/metrics-server/issues/55#issuecomment-387229420"&gt;&lt;time&gt;May 07, 2018&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;p&gt;kube-state-metrics focuses on&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;...on the health of the various objects inside, such as deployments, nodes and pods.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;metrics-server on the other hand implements the &lt;a href="https://github.com/kubernetes/community/blob/master/contributors/design-proposals/instrumentation/resource-metrics-api.md"&gt;Resource Metrics API
&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;To summarize in a sentence: kube-state-metrics exposes metrics for all sorts of Kubernetes objects. metrics-server only exposes very few metrics to Kubernetes itself (not scrapable directly with Prometheus), like node &amp;amp; pod utilization.&lt;/p&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/kubernetes-sigs/metrics-server/issues/55#issuecomment-387229420"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;Looking at the logs of prometheus server and kube-state-metrics nothing jumped out of ordinary.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a&gt;Finally&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;I asked for help, I explained what I have done so far and my team mate suggested the obvious, did you check if the query works!!&lt;/p&gt;

&lt;p&gt;so I went to prometheus query explorer and executed&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;container_cpu_usage_seconds_total{namespace="xxx", pod_name="xxx-worker-6c5bd59857-xxxxx"}

Returned no results

container_cpu_usage_seconds_total{namespace="xxx"}

Returned results

container_cpu_usage_seconds_total{namespace="xxx", pod="xxx-worker-6c5bd59857-xxxxx"}

Returned results
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  🤔 What does this mean? 🤔
&lt;/h3&gt;

&lt;p&gt;So some where during the EKS version upgrade the support for label &lt;code&gt;pod_name&lt;/code&gt; is &lt;a href="https://github.com/kubernetes/kubernetes/pull/80376/commits/e0b66c792b8daabc8f2dcc5209356bca2cb2b197"&gt;dropped&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;After fixing the queries in grafana, I could see the metrics finally.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--leA0no1W--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgflip.com/42nepy.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--leA0no1W--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgflip.com/42nepy.jpg" alt="case closed"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Lessons Learned
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Learn the components and its purpose before assuming&lt;/li&gt;
&lt;li&gt;Always read the release notes when &lt;a href="https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.16.md#removed-metrics"&gt;upgrading even minor versions&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Removed cadvisor metric labels pod_name and container_name to match instrumentation guidelines. Any Prometheus queries that match pod_name and container_name labels (e.g. cadvisor or kubelet probe metrics) must be updated to use pod and container instead. (#80376, @ehashman)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;The solution is always the obvious solution
&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NpNZI_ld--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgflip.com/42nqn2.jpg" alt="do not overthink just because it is kubernetes"&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;I welcome all constructive feedback and comments&lt;/em&gt;&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>devops</category>
      <category>prometheus</category>
      <category>aws</category>
    </item>
    <item>
      <title>Microservices - Why wait for your Integration tests to fail when you have Pact?</title>
      <dc:creator>Shyamala</dc:creator>
      <pubDate>Tue, 02 Apr 2019 19:08:22 +0000</pubDate>
      <link>https://forem.com/shyamala_u/microservices-why-wait-for-your-integration-tests-to-fail-when-you-have-pact-2acd</link>
      <guid>https://forem.com/shyamala_u/microservices-why-wait-for-your-integration-tests-to-fail-when-you-have-pact-2acd</guid>
      <description>&lt;p&gt;With more and more software moving from monolith to microservices, we are swamped in the world of more APIs than ever. How can we write APIs that are meaningful, precise , testable and maintainable? Once an API is out there we are obligated not to break them or alternatively we have to know before hand that we have breaking changes. &lt;/p&gt;

&lt;p&gt;In this post I try to put together my experience on how Pact (&lt;a href="https://docs.pact.io"&gt;https://docs.pact.io&lt;/a&gt;) helps us in writing better APIs in our microservices architecture.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a Pact?
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Pact (noun):&lt;br&gt;
A formal agreement between individuals or parties.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;According to &lt;a href="https://pact.io"&gt;&lt;code&gt;Pact Foundation&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Pact is a &lt;code&gt;contract testing tool&lt;/code&gt;. Contract testing is a way to ensure that services (such as an API provider and a consumer) can communicate with each other. Without contract testing, the only way to know that services can communicate is by using expensive and brittle integration tests.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Parties
&lt;/h2&gt;

&lt;p&gt;Any API(Application Programming Interface) consists of two important parties:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Provider:&lt;/strong&gt; One who exposes one or more API(s)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Consumer(s)&lt;/strong&gt;: One or more client(s) who uses the API(s) exposed by the Provider&lt;/p&gt;

&lt;h2&gt;
  
  
  How does a Pact work?
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;Consumer captures an expectation&lt;/code&gt; as a separate pact, and &lt;code&gt;provider agrees to it&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Advantages of using Pacts
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Isolation:
&lt;/h3&gt;

&lt;p&gt;The Ability to test the provider and consumer &lt;strong&gt;in Isolation but in conjunction&lt;/strong&gt;, i.e. Pacts gives us the sophistication of&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;testing a consumer with provider's API from the comfort of a developer's machine Without having to make an actual call.&lt;/li&gt;
&lt;li&gt;testing a provider's API changes against one or more consumers to make sure that the changes do not accidentally break the existing consumers&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Quick Feedback
&lt;/h3&gt;

&lt;p&gt;We do not have to wait for our End to End tests to fail, the same feedback can be unit tested.&lt;/p&gt;

&lt;h3&gt;
  
  
  User Centred API design
&lt;/h3&gt;

&lt;p&gt;Pacts are essentially &lt;code&gt;Consumer Driven Contracts&lt;/code&gt;, so the consumers are laying out the expectation which leads to better usable APIs&lt;/p&gt;

&lt;h3&gt;
  
  
  Overview of existing APIs
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Pacts provides &lt;code&gt;Network Graph&lt;/code&gt; of dependant services&lt;/li&gt;
&lt;li&gt;Pacts helps us understand, if &lt;code&gt;one or more APIs are similar&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Pacts can also show &lt;code&gt;unused APIs&lt;/code&gt;, when the consumers are not using them anymore.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Language independent
&lt;/h3&gt;

&lt;p&gt;Pact is a &lt;a href="https://github.com/pact-foundation/pact-specification#index"&gt;specification&lt;/a&gt;, which makes it perfect for microservices testing. You can find Pact consumer and provider libraries implemented in many programming languages &lt;a href="https://github.com/pact-foundation"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Pact in Action:
&lt;/h2&gt;

&lt;h3&gt;
  
  
  An Example Pact
&lt;/h3&gt;

&lt;p&gt;Let us take the most simple use case of authentication as a service.&lt;/p&gt;

&lt;p&gt;Consumer: I need to log the user in, I have user credentials&lt;br&gt;
Provider: I can authenticate a user given credentials&lt;/p&gt;

&lt;p&gt;For demonstration, we use the same pact as described above. Complete implementation can be found &lt;a href="https://github.com/shyamz-22/Pactit"&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Consumer Pact in Go:
&lt;/h3&gt;


&lt;div class="highlight"&gt;&lt;pre class="highlight go"&gt;&lt;code&gt;    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="s"&gt;"fmt"&lt;/span&gt;
        &lt;span class="s"&gt;"github.com/pact-foundation/pact-go/dsl"&lt;/span&gt;
        &lt;span class="s"&gt;"net/http"&lt;/span&gt;
        &lt;span class="s"&gt;"testing"&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;TestClient_AuthenticateUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;testing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

        &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"alice"&lt;/span&gt;
        &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"s3cr3t"&lt;/span&gt;

        &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"user exists"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;testing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;pact&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;dsl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Pact&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;Consumer&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"Quoki"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;Provider&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"UserManager"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="n"&gt;PactDir&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="s"&gt;"../pacts"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="n"&gt;LogDir&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;   &lt;span class="s"&gt;"../pacts/logs"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;pact&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Teardown&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

            &lt;span class="n"&gt;pact&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
                &lt;span class="n"&gt;AddInteraction&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
                &lt;span class="n"&gt;Given&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"user exists"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
                &lt;span class="n"&gt;UponReceiving&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"a request to authenticate"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
                &lt;span class="n"&gt;WithRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dsl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="n"&gt;Method&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="s"&gt;"POST"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;    &lt;span class="n"&gt;dsl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/users/%s/authentication"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
                    &lt;span class="n"&gt;Headers&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;dsl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MapMatcher&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"Content-Type"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;dsl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Like&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"application/x-www-form-urlencoded"&lt;/span&gt;&lt;span class="p"&gt;)},&lt;/span&gt;
                    &lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;dsl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MapMatcher&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="s"&gt;"password"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;dsl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Like&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                    &lt;span class="p"&gt;},&lt;/span&gt;
                &lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
                &lt;span class="n"&gt;WillRespondWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dsl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="n"&gt;Status&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusNoContent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="p"&gt;})&lt;/span&gt;

        &lt;span class="n"&gt;pact&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Verify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;subject&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"http://localhost:%d"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pact&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Server&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Port&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
                &lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;subject&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AuthenticateUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fail&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;

                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
            &lt;span class="p"&gt;})&lt;/span&gt;

        &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Running this successfully will generate,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"consumer"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Quoki"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"provider"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"UserManager"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"interactions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"a request to authenticate"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"providerState"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"user exists"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"request"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"method"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"POST"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"path"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/users/alice/authentication"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"headers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"Content-Type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"application/x-www-form-urlencoded"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"body"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"password=s3cr3t"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"matchingRules"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"$.headers.Content-Type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"match"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"type"&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="nl"&gt;"$.body.password"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"match"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"type"&lt;/span&gt;&lt;span class="w"&gt;
              &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"response"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;204&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"headers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"metadata"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"pactSpecification"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2.0.0"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Provider verification of Pact in Kotlin
&lt;/h3&gt;

&lt;p&gt;The Provider then takes this as requirement, then verifies by running this test&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight kotlin"&gt;&lt;code&gt;    &lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;com.shyamz.provider.authenticate&lt;/span&gt;

    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;au.com.dius.pact.provider.junit.Consumer&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;au.com.dius.pact.provider.junit.Provider&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;au.com.dius.pact.provider.junit.State&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;au.com.dius.pact.provider.junit.loader.PactFolder&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;au.com.dius.pact.provider.junit.target.HttpTarget&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;au.com.dius.pact.provider.junit.target.Target&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;au.com.dius.pact.provider.junit.target.TestTarget&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;au.com.dius.pact.provider.spring.SpringRestPactRunner&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.junit.Before&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.junit.runner.RunWith&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.springframework.beans.factory.annotation.Autowired&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.springframework.boot.test.context.SpringBootTest&lt;/span&gt;


    &lt;span class="nd"&gt;@RunWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;SpringRestPactRunner&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nd"&gt;@Provider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"UserManager"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nd"&gt;@Consumer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Quoki"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nd"&gt;@PactFolder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"../consumer/src/consumer/http/pacts"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nd"&gt;@SpringBootTest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;webEnvironment&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;SpringBootTest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;WebEnvironment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;DEFINED_PORT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;properties&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"server.port=8601"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;QuokiUserAuthenticatePactItTest&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

        &lt;span class="nd"&gt;@Suppress&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"unused"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nd"&gt;@JvmField&lt;/span&gt;
        &lt;span class="nd"&gt;@TestTarget&lt;/span&gt;
        &lt;span class="k"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;target&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Target&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;HttpTarget&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;8601&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="nd"&gt;@Autowired&lt;/span&gt;
        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;lateinit&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;userRepository&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;UserRepository&lt;/span&gt;

        &lt;span class="nd"&gt;@Before&lt;/span&gt;
        &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;setUp&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;userRepository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;deleteAll&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="nd"&gt;@State&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"user exists"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;userExists&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;userRepository&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;QuokiUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"alice"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"s3cr3t"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Running this will provide the result&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    Verifying a pact between Quoki and UserManager
    Given user exists
        a request to authenticate
    returns a response which
        has status code 204 (OK)
        has a matching body (OK)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Best Practices
&lt;/h2&gt;

&lt;h3&gt;
  
  
  A Bad Pact
&lt;/h3&gt;

&lt;p&gt;A bad pact, dictates what it considers as a precondition for an invalid username and tightly couples the exact error message that is expected.&lt;/p&gt;

&lt;p&gt;This is then unit testing the provider's implementation detail rather than the contract itself. So the provider cannot change the validation rule or the error message without breaking the consumer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Given :&lt;/strong&gt; Alice does not exist&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Upon receiving:&lt;/strong&gt; A request to create user, with user name that has special characters other than underscores&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Response:&lt;/strong&gt; Is 400 Bad Request&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Response Body:&lt;/strong&gt; {"error": "username cannot contain special characters"}&lt;/p&gt;

&lt;h3&gt;
  
  
  A Good Pact
&lt;/h3&gt;

&lt;p&gt;A Good pact from a consumer &lt;strong&gt;hides the provider's implementation details. It must only capture expectation from consumer point of view&lt;/strong&gt;. In the below example a consumer shall not dictate what it considers an invalid username.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Given :&lt;/strong&gt; Alice does not exist&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Upon receiving:&lt;/strong&gt; A request to create user with invalid username&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Response:&lt;/strong&gt; Is 400 Bad Request&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Response Body:&lt;/strong&gt; {"error": "[a non empty string]"}&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;If you have more questions or if you need more information, you can find all the information &lt;a href="https://docs.pact.io/"&gt;here&lt;/a&gt;&lt;/p&gt;

</description>
      <category>microservices</category>
      <category>pact</category>
      <category>testing</category>
    </item>
    <item>
      <title>Spring boot + Spring Security 5 + OAuth2/OIDC Client - Deep Dive</title>
      <dc:creator>Shyamala</dc:creator>
      <pubDate>Mon, 25 Mar 2019 21:51:04 +0000</pubDate>
      <link>https://forem.com/shyamala_u/spring-boot--spring-security-5--oauth2oidc-client---deep-dive-261l</link>
      <guid>https://forem.com/shyamala_u/spring-boot--spring-security-5--oauth2oidc-client---deep-dive-261l</guid>
      <description>&lt;p&gt;In my &lt;a href="https://dev.to/shyamala_u/spring-boot--spring-security-5--oauth2oidc-client---basics-4ibo"&gt;previous post&lt;/a&gt; we saw how easy it is to protect your application with Google Login.&lt;/p&gt;

&lt;p&gt;Now let us see what are all the components responsible for this to work.&lt;/p&gt;

&lt;h1&gt;
  
  
  The Login process
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Request to access the protected Endpoint and Google Authentication process starts
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Prerequisites&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;application.yml&lt;/code&gt; is &lt;a href="https://dev.to/shyamala_u/spring-boot--spring-security-5--oauth2oidc-client---basics-4ibo#step-3"&gt;configured&lt;/a&gt; with client and provider values&lt;/li&gt;
&lt;li&gt;Provider name in the property &lt;code&gt;spring.security.oauth2.client.registration.provider&lt;/code&gt; is set to google&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;When access to &lt;code&gt;http://localhost:8080/me&lt;/code&gt; is requested, If you have only one identity provider configured then, Spring redirects you automatically to &lt;code&gt;http://localhost:8080/oauth2/authorization/google&lt;/code&gt;. &lt;code&gt;OAuth2AuthorizationRequestRedirectFilter&lt;/code&gt; which is registered to the url pattern &lt;code&gt;/oauth2/authorization/*&lt;/code&gt; will load the respective configuration and redirect to the Identity Provider. In our case Google.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you want your users to choose between multiple providers, then configure your &lt;code&gt;application.yml&lt;/code&gt; for multiple providers, but you need a login page where you can have multiple links for the users to choose from.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  On Successful authentication google redirects to the app's redirect url
&lt;/h2&gt;

&lt;p&gt;Once the user authenticates with Google successfully, Google now redirects to the app's redirect url configured in Google's developer console. In our example we chose to have a particular url &lt;code&gt;http://localhost:8080/login/oauth2/code/google&lt;/code&gt;. This is because the Authentication Processing filter for OAuth2 &lt;code&gt;OAuth2LoginAuthenticationFilter&lt;/code&gt; is registered to listen to &lt;code&gt;/login/oauth2/code/*&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;OAuth2LoginAuthenticationFilter delegates authentication to &lt;code&gt;OidcAuthorizationCodeAuthenticationProvider&lt;/code&gt; which does 3 things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Exchanges Code for token&lt;/li&gt;
&lt;li&gt;Validates id_token&lt;/li&gt;
&lt;li&gt;Populates User Info by calling the User Info endpoint, from Google's well known configuration&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now you might ask what if I have registered a different redirect URI, and want OAuth2LoginAuthenticationFilter to listen to this. It is pretty simple all you need to do is have the following Security Configuration&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Configuration&lt;/span&gt;
&lt;span class="nd"&gt;@EnableWebSecurity&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SecurityConfiguration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;WebSecurityConfigurerAdapter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;configure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;HttpSecurity&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;http&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;authorizeRequests&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;anyRequest&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;authenticated&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;and&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;oauth2Login&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;redirectionEndpoint&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;baseUri&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/oauth/callback/*"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What Next
&lt;/h2&gt;

&lt;p&gt;As a result of successful authentication, you will get an Authentication object of type &lt;code&gt;OAuth2AuthenticationToken&lt;/code&gt;. This token will contain all the necessary information from &lt;code&gt;id_token&lt;/code&gt; and the &lt;code&gt;user info endpoint&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You can access all data about the logged in user  by&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nc"&gt;SecurityContextHolder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getContext&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;authentication&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nc"&gt;OAuth2AuthenticationToken&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt; &lt;span class="nd"&gt;@GetMapping&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/me"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;currentUser&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;OAuth2AuthenticationToken&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;ResponseEntity&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;OAuth2AuthenticationToken&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;ResponseEntity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;currentUser&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  But what about Access and Refresh Tokens?
&lt;/h2&gt;

&lt;p&gt;As a result of successful OpenID Connect flow, a client application receives three tokens, &lt;code&gt;access_token, refresh_token and id_token&lt;/code&gt;. We might want to use this access token to access some protected resource from a resource server &lt;a href="https://developers.google.com/tasks/v1/reference/tasks/list"&gt;like tasks API of google&lt;/a&gt;. The &lt;code&gt;OAuth2AuthorizedClientService&lt;/code&gt; keeps track of the tokens associated with the user.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;currentUser&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;SecurityContextHolder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getContext&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;authentication&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nc"&gt;OAuth2AuthenticationToken&lt;/span&gt;
 &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;currentUserClientConfig&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;oAuth2AuthorizedClientService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loadAuthorizedClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;authorizedClientRegistrationId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;currentUser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nf"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"AccessToken: ${currentUserClientConfig.accessToken.tokenValue}"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nf"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"RefreshToken: ${currentUserClientConfig.refreshToken.tokenValue}"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  But Access Tokens can expire
&lt;/h2&gt;

&lt;p&gt;When access tokens expire, the resource server like &lt;a href="https://developers.google.com/tasks/v1/reference/tasks/list"&gt;like tasks API of google&lt;/a&gt; will return 401 HTTP status, the simplest solution is to throw an &lt;code&gt;OAuth2AuthorizationException&lt;/code&gt; which is a type of &lt;code&gt;AuthenticationException&lt;/code&gt; that will trigger the login flow again. &lt;/p&gt;

&lt;p&gt;But we can also use Refresh Tokens to automatically refresh our tokens, by customizing &lt;code&gt;RestTemplate&lt;/code&gt; with a request interceptor that will refresh the tokens on expiry&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BearerTokenInterceptor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;oAuth2AuthorizedClientService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;OAuth2AuthorizedClientService&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;ClientHttpRequestInterceptor&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;companion&lt;/span&gt; &lt;span class="k"&gt;object&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;log&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Logger&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;LoggerFactory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getLogger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;BearerTokenInterceptor&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;java&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;accessTokenExpiresSkew&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Duration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ofMinutes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;clock&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Clock&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;systemUTC&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;intercept&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;HttpRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;ByteArray&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;execution&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;ClientHttpRequestExecution&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;ClientHttpResponse&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;currentUser&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;SecurityContextHolder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getContext&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;authentication&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nc"&gt;OAuth2AuthenticationToken&lt;/span&gt;
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;currentUserClientConfig&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;currentUser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;clientConfig&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;isExpired&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;accessToken&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;currentUserClientConfig&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;accessToken&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"AccessToken expired, refreshing automatically"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="nf"&gt;refreshToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;currentUserClientConfig&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;currentUser&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;AUTHORIZATION&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Bearer ${currentUserClientConfig.accessToken.tokenValue}"&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;execution&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nc"&gt;OAuth2AuthenticationToken&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;clientConfig&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nc"&gt;OAuth2AuthorizedClient&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;oAuth2AuthorizedClientService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loadAuthorizedClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;authorizedClientRegistrationId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;?:&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nc"&gt;CredentialsExpiredException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"could not load client config for $name, reauthenticate"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;refreshToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;currentClient&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;OAuth2AuthorizedClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;currentUser&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;OAuth2AuthenticationToken&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;atr&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;refreshTokenClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;currentClient&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;atr&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt; &lt;span class="p"&gt;||&lt;/span&gt; &lt;span class="n"&gt;atr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;accessToken&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Failed to refresh token for ${currentUser.name}"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;refreshToken&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;atr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;refreshToken&lt;/span&gt; &lt;span class="o"&gt;?:&lt;/span&gt; &lt;span class="n"&gt;currentClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;refreshToken&lt;/span&gt;
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;updatedClient&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;OAuth2AuthorizedClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;currentClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;clientRegistration&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;currentClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;principalName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;atr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;accessToken&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;refreshToken&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;oAuth2AuthorizedClientService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;saveAuthorizedClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;updatedClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;currentUser&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;refreshTokenClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;currentClient&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;OAuth2AuthorizedClient&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;OAuth2AccessTokenResponse&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;formParameters&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;LinkedMultiValueMap&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;()&lt;/span&gt;
        &lt;span class="n"&gt;formParameters&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;OAuth2ParameterNames&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;GRANT_TYPE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;AuthorizationGrantType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;REFRESH_TOKEN&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;formParameters&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;OAuth2ParameterNames&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;REFRESH_TOKEN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;currentClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;refreshToken&lt;/span&gt;&lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="n"&gt;tokenValue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;formParameters&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;OAuth2ParameterNames&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;REDIRECT_URI&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;currentClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;clientRegistration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;redirectUriTemplate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;requestEntity&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;RequestEntity&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;URI&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;currentClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;clientRegistration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;providerDetails&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tokenUri&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;header&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;CONTENT_TYPE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;APPLICATION_FORM_URLENCODED_VALUE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;body&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;formParameters&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;r&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;restTemplate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;currentClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;clientRegistration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;clientId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;currentClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;clientRegistration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;clientSecret&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;responseEntity&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exchange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;requestEntity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;OAuth2AccessTokenResponse&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;java&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;responseEntity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;OAuth2AuthorizationException&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Unable to refresh token ${e.error.errorCode}"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nc"&gt;OAuth2AuthenticationException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;isExpired&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;accessToken&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;OAuth2AccessToken&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;Boolean&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;now&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;clock&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;instant&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;expiresAt&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;accessToken&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;expiresAt&lt;/span&gt; &lt;span class="o"&gt;?:&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isAfter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;expiresAt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;minus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;accessTokenExpiresSkew&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;restTemplate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;clientId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;clientSecret&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;RestTemplate&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;RestTemplateBuilder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;additionalMessageConverters&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                        &lt;span class="nc"&gt;FormHttpMessageConverter&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
                        &lt;span class="nc"&gt;OAuth2AccessTokenResponseHttpMessageConverter&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;errorHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;OAuth2ErrorResponseErrorHandler&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;basicAuthentication&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;clientId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;clientSecret&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;So far I have not found that the oauth2-client can automatically refresh tokens within the user session, Let me know if this is the case :)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;I tried to put together all pieces involved, Please give me feedback if I missed something :)&lt;/p&gt;

</description>
      <category>oauth2</category>
      <category>java</category>
      <category>spring</category>
      <category>springsecurity</category>
    </item>
    <item>
      <title>Spring boot + Spring Security 5 + OAuth2/OIDC Client - Basics</title>
      <dc:creator>Shyamala</dc:creator>
      <pubDate>Sun, 24 Mar 2019 17:45:04 +0000</pubDate>
      <link>https://forem.com/shyamala_u/spring-boot--spring-security-5--oauth2oidc-client---basics-4ibo</link>
      <guid>https://forem.com/shyamala_u/spring-boot--spring-security-5--oauth2oidc-client---basics-4ibo</guid>
      <description>&lt;p&gt;Since a long time I wanted to integrate an OpenID Connect provider using Spring Security, The last time I tried, I felt it was very complicated and wrote my own &lt;a href="https://github.com/shyamz-22/openid-connect-client"&gt;library&lt;/a&gt;. Since Spring Security 5 has native support for OAuth2 Client and extended its use for OpenID connect, I wanted to see how easy it is to integrate.&lt;/p&gt;

&lt;p&gt;For this example we are going to build a simple app, the redirects to google when we try to access a protected endpoint&lt;/p&gt;

&lt;h1&gt;
  
  
  Step 1:
&lt;/h1&gt;

&lt;p&gt;Create a spring boot project from &lt;a href="https://start.spring.io"&gt;https://start.spring.io&lt;/a&gt; with following dependencies&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight groovy"&gt;&lt;code&gt;&lt;span class="n"&gt;dependencies&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;implementation&lt;/span&gt; &lt;span class="s1"&gt;'org.springframework.boot:spring-boot-starter-oauth2-client'&lt;/span&gt;
    &lt;span class="n"&gt;implementation&lt;/span&gt; &lt;span class="s1"&gt;'org.springframework.boot:spring-boot-starter-security'&lt;/span&gt;
    &lt;span class="n"&gt;implementation&lt;/span&gt; &lt;span class="s1"&gt;'org.springframework.boot:spring-boot-starter-web'&lt;/span&gt;
    &lt;span class="n"&gt;implementation&lt;/span&gt; &lt;span class="s1"&gt;'com.fasterxml.jackson.module:jackson-module-kotlin'&lt;/span&gt;
    &lt;span class="n"&gt;implementation&lt;/span&gt; &lt;span class="s1"&gt;'org.jetbrains.kotlin:kotlin-reflect'&lt;/span&gt;
    &lt;span class="n"&gt;implementation&lt;/span&gt; &lt;span class="s1"&gt;'org.jetbrains.kotlin:kotlin-stdlib-jdk8'&lt;/span&gt;
    &lt;span class="n"&gt;testImplementation&lt;/span&gt; &lt;span class="s1"&gt;'org.springframework.boot:spring-boot-starter-test'&lt;/span&gt;
    &lt;span class="n"&gt;testImplementation&lt;/span&gt; &lt;span class="s1"&gt;'org.springframework.security:spring-security-test'&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h1&gt;
  
  
  Step 2:
&lt;/h1&gt;

&lt;p&gt;Create an endpoint that will show current user's authentication data&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@RestController&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;HelloController&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@GetMapping&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/me"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;currentUser&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;OAuth2AuthenticationToken&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;ResponseEntity&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;OAuth2AuthenticationToken&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;ResponseEntity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;currentUser&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h1&gt;
  
  
  Step 3:
&lt;/h1&gt;

&lt;p&gt;Configure OAuth2 Client information in application.yml. In google's developer console configure the app's redirect uri as &lt;code&gt;http://localhost:8080/login/oauth2/code/google&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# @see https://console.developers.google.com/apis/ to create your client credentials&lt;/span&gt;
&lt;span class="s"&gt;logging.level.org.springframework&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;INFO&lt;/span&gt;
&lt;span class="na"&gt;spring&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;security&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;oauth2&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;client&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;registration&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;google&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;provider&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;google&lt;/span&gt;
            &lt;span class="na"&gt;client-id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;&amp;lt;your-client-id&amp;gt;&amp;gt;&lt;/span&gt;
            &lt;span class="na"&gt;client-secret&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;&amp;lt;your-client-secret&amp;gt;&amp;gt;&lt;/span&gt; 
            &lt;span class="na"&gt;client-authentication-method&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;basic&lt;/span&gt;
            &lt;span class="na"&gt;authorization-grant-type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;authorization_code&lt;/span&gt;
            &lt;span class="na"&gt;scope&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;openid&lt;/span&gt;
              &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;email&lt;/span&gt;
              &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;profile&lt;/span&gt;
              &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;https://www.googleapis.com/auth/tasks.readonly&lt;/span&gt;
        &lt;span class="na"&gt;provider&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;google&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;issuer-uri&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://accounts.google.com&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h1&gt;
  
  
  Step 4:
&lt;/h1&gt;

&lt;p&gt;Run the application, goto &lt;a href="http://localhost:8080/me"&gt;http://localhost:8080/me&lt;/a&gt; , complete the login process and you will see this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"authorities"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"authority"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ROLE_USER"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"attributes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"at_hash"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"28AV0o6xKM8f3UQlljlGuw"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"sub"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"10080000000000000"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"email_verified"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"iss"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://accounts.google.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"given_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Syamala"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"locale"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"en"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"picture"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://lh6.googleusercontent.com/photo.jpg"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"aud"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="s2"&gt;"client-id"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"azp"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"client-id"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Syamala Umamaheswaran"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"exp"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2019-03-24T18:27:19Z"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"family_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Umamaheswaran"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"iat"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2019-03-24T17:27:19Z"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"xxxx@gmail.com"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"idToken"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"userInfo"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"details"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"authenticated"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"principal"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"authorizedClientRegistrationId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"google"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"credentials"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"10080000000000000"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h1&gt;
  
  
  Mind Blown:
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/3ohc0Xk1JCH35wvrVu/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/3ohc0Xk1JCH35wvrVu/giphy.gif" alt="Mind Blown"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As much as it blows my mind that without writing any code for security we are able to integrate with an OpenID Connect provider, I needed to know how this is working so easily. The Devil is in the details, Stay tuned for my &lt;a href="https://dev.to/shyamala_u/spring-boot--spring-security-5--oauth2oidc-client---deep-dive-261l"&gt;next blog post&lt;/a&gt; where I explain the behind the scenes and How to access a protected resource and how to refresh tokens automatically. &lt;/p&gt;

&lt;p&gt;Complete Source Code @ &lt;a href="https://github.com/shyamz-22/oidc-spring-security-5"&gt;https://github.com/shyamz-22/oidc-spring-security-5&lt;/a&gt;&lt;/p&gt;

</description>
      <category>oauth2</category>
      <category>java</category>
      <category>springboot</category>
      <category>springsecurity</category>
    </item>
    <item>
      <title>Beyond the login screen - Part II</title>
      <dc:creator>Shyamala</dc:creator>
      <pubDate>Mon, 12 Mar 2018 03:03:45 +0000</pubDate>
      <link>https://forem.com/shyamala_u/beyond-the-login-screen---part-ii--450n</link>
      <guid>https://forem.com/shyamala_u/beyond-the-login-screen---part-ii--450n</guid>
      <description>&lt;p&gt;In &lt;a href="https://dev.to/shyamala_u/beyond-the-login-screen---part-i--29g3"&gt;Previous&lt;/a&gt; post, we reasoned around why transparency while collecting user data is important. In this part let us dig deeper into one of the Open Standards OpenID Connect and see how the standard gives flexibility and transparency around user data management.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Familiar OAuth2 dance
&lt;/h2&gt;

&lt;p&gt;OpenID Connect is built on top of OAuth2,&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_FF-J4zQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/q6qv6y3adoe6zwakir2n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_FF-J4zQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/q6qv6y3adoe6zwakir2n.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Before jumping on to technicalities of OpenID Connect, let us brush our memory on how we &lt;code&gt;(The Users)&lt;/code&gt; are used to signing in with Google &lt;code&gt;(The Identity Provider)&lt;/code&gt; to Meetup &lt;code&gt;(The App)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Move 1:&lt;/strong&gt; User goes to &lt;code&gt;Meetup&lt;/code&gt; app and clicks on log in with &lt;code&gt;Google&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Move 2:&lt;/strong&gt; &lt;code&gt;Meetup&lt;/code&gt; app then asks &lt;code&gt;Google&lt;/code&gt; to authenticate the user and share the &lt;code&gt;basic profile&lt;/code&gt; of the User&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Move 3:&lt;/strong&gt; &lt;code&gt;Google&lt;/code&gt; then asks the &lt;code&gt;user&lt;/code&gt; to login&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Move 4:&lt;/strong&gt; On successful authentication of the &lt;code&gt;user&lt;/code&gt;, &lt;code&gt;Google&lt;/code&gt; now asks &lt;code&gt;User&lt;/code&gt; if it is ok for them to share their &lt;code&gt;basic profile&lt;/code&gt; with &lt;code&gt;Meetup&lt;/code&gt; and &lt;code&gt;User&lt;/code&gt; &lt;strong&gt;consents&lt;/strong&gt; to &lt;code&gt;Google&lt;/code&gt; to share their data to &lt;code&gt;Meetup&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Move 5:&lt;/strong&gt; &lt;code&gt;Google&lt;/code&gt; now shares an ephemeral Key to &lt;code&gt;Meetup&lt;/code&gt; that can unlock the &lt;code&gt;User's&lt;/code&gt; &lt;strong&gt;consented&lt;/strong&gt; data  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Move 6:&lt;/strong&gt; &lt;code&gt;Meetup&lt;/code&gt; uses the key to get &lt;code&gt;Basic profile&lt;/code&gt; data.&lt;/p&gt;

&lt;h2&gt;
  
  
  What User Data?
&lt;/h2&gt;

&lt;p&gt;At Move 2, &lt;code&gt;Meetup&lt;/code&gt; knows that it only needs &lt;code&gt;basic profile&lt;/code&gt; data like &lt;code&gt;Name&lt;/code&gt;, &lt;code&gt;email&lt;/code&gt; and &lt;code&gt;profile picture&lt;/code&gt; to complete its user profile.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why User Data?
&lt;/h2&gt;

&lt;p&gt;At Move 4, &lt;code&gt;Google&lt;/code&gt; asks the &lt;code&gt;User's&lt;/code&gt; &lt;strong&gt;consent&lt;/strong&gt; to share the data to &lt;code&gt;Meetup&lt;/code&gt; explaining that this will be used as a profile.&lt;/p&gt;

&lt;h2&gt;
  
  
  Flexibility and Transparency
&lt;/h2&gt;

&lt;p&gt;Now replace &lt;code&gt;Google&lt;/code&gt; with your own Identity Provider, then you have achieved a new level of flexibility towards transparent data management.&lt;/p&gt;

&lt;p&gt;Assume Meetup needs this new feature, that can show meetups nearby, So now Meetup app needs to know the postal code of the user, all Meetup app now needs to do is request for a new scope &lt;code&gt;pincode&lt;/code&gt; along with &lt;code&gt;basic_profile&lt;/code&gt; and now the Identity Provider would ask consent for the newly added scope to user.&lt;/p&gt;

&lt;h2&gt;
  
  
  Behind the scenes
&lt;/h2&gt;

&lt;p&gt;If you know the dance, you can skip to Conclusion. If you want to learn the moves, continue reading&lt;/p&gt;

&lt;h3&gt;
  
  
  Move 1&lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;User goes to &lt;code&gt;Meetup&lt;/code&gt; app and clicks on log in with &lt;code&gt;Google&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In order for this to be possible,The App should register itself with the Identity Provider, by providing minimum the Name it wants its Users to see in Move 4 and a url for the Identity Provider to communicate the result to.&lt;/p&gt;

&lt;p&gt;This is &lt;a href="https://openid.net/specs/openid-connect-registration-1_0.html"&gt;Client Registration&lt;/a&gt;. As a result of registration now the App gets an Id and a Secret.&lt;/p&gt;

&lt;h3&gt;
  
  
  Move 2&lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;Meetup&lt;/code&gt; app then asks &lt;code&gt;Google&lt;/code&gt; to authenticate the user and share the &lt;code&gt;basic profile&lt;/code&gt; of the User&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now The app forms a request with its Id and registered Url and requests for a &lt;code&gt;scope&lt;/code&gt; e.g. Basic Profile using &lt;code&gt;response_type&lt;/code&gt; one of the three flows (Basic, Implicit or Hybrid) to receive the user's data&lt;/p&gt;

&lt;p&gt;This is an &lt;a href="https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest"&gt;Authentication Request&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Move 3&lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;Google&lt;/code&gt; then asks the &lt;code&gt;user&lt;/code&gt; to login&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;At this point The Identity Provider checks for the validity of client (id and registered url), and asks the user to login.&lt;/p&gt;

&lt;p&gt;This is an Identity Provider doing its identity thing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Move 4&lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;Google&lt;/code&gt; now asks &lt;code&gt;User&lt;/code&gt; if it is ok for them to share their &lt;code&gt;basic profile&lt;/code&gt; with &lt;code&gt;Meetup&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;On successful authentication, now Identity Provider shows the consent screen to the user describing the&lt;br&gt;
what data the app needs and why.&lt;/p&gt;

&lt;p&gt;This is Getting the user's consent&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;How user gets authenticated or consents is out of scope for the OpenID Connect standard.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Move 5&lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;Google&lt;/code&gt; now shares an ephemeral Key to &lt;code&gt;Meetup&lt;/code&gt; that can unlock the &lt;code&gt;User's&lt;/code&gt; &lt;strong&gt;consented&lt;/strong&gt; data  &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;On successful authentication and receiving user's consent, Now Identity Provider has to share this with the App. How this information is shared to the app is decided by the &lt;code&gt;response_type&lt;/code&gt; value provided by the app in Move 1&lt;/p&gt;

&lt;p&gt;The end result of any flow (Basic, Implicit, Hybrid) is generating one or more of &lt;code&gt;access_token&lt;/code&gt; &lt;code&gt;refresh_token&lt;/code&gt; and &lt;code&gt;id_token&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This is &lt;a href="https://openid.net/specs/openid-connect-core-1_0.html#TokenResponse"&gt;successful token response&lt;/a&gt; from &lt;a href="https://openid.net/specs/openid-connect-core-1_0.html#TokenEndpoint"&gt;token endpoint&lt;/a&gt; for Basic and Hybrid flows or &lt;a href="https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest"&gt;authorize endpoint&lt;/a&gt; for Implicit flow.&lt;/p&gt;

&lt;h4&gt;
  
  
  Choosing flows
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ItLK3-hF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/kv19qcqfwahq3q8nwmpy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ItLK3-hF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/kv19qcqfwahq3q8nwmpy.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Move 6&lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;Meetup&lt;/code&gt; uses the key to get &lt;code&gt;Basic profile&lt;/code&gt; data.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now the App can use this short lived &lt;code&gt;access_token&lt;/code&gt; to get information about user.&lt;/p&gt;

&lt;p&gt;This is &lt;a href="https://openid.net/specs/openid-connect-core-1_0.html#UserInfo"&gt;User Info endpoint&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The Questions we need to ask,
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PfBwGL1C--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/u60yc2chlby6tsiphflz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PfBwGL1C--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/u60yc2chlby6tsiphflz.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So Identity Provider can validate App and User,  But &lt;strong&gt;How does the App know&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It is indeed &lt;code&gt;The Identity Provider&lt;/code&gt; that authenticated the user and responded to it?&lt;/li&gt;
&lt;li&gt;How long since the user was last authenticated? Given all the SSO convenience going on?&lt;/li&gt;
&lt;li&gt;With which level of security (1FA or 2FA) the user was authenticated? Given the App deals with of course money, we need to have iron clad security don't we?&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The Answer is &lt;code&gt;id_token&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;This is what makes OpenID Connect different about OAuth2, It provides an Identity layer on top of the OAuth2 standard. It gives feedback to the App about the authenticated user.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Ickk7tOl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/75gty0dmvj8zyafmb1kj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Ickk7tOl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/75gty0dmvj8zyafmb1kj.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can think of &lt;a href="https://openid.net/specs/openid-connect-core-1_0.html#IDToken"&gt;id_token&lt;/a&gt; as digital secure identity card of the user. It is a &lt;a href="https://jwt.io"&gt;JWT&lt;/a&gt; token signed by the &lt;code&gt;Identity Provider's&lt;/code&gt; private key. The Public key is shared through &lt;a href="https://tools.ietf.org/html/rfc7517"&gt;keys endpoint&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion&lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;By abstracting away authentication and authorization data of the user we can achieve flexibility on how and when to collect the data there by building up a User Profile. The Identity Provider can define scopes, that allows an App to not only get user data but also to write user data through Scope Management.&lt;/p&gt;

&lt;p&gt;And the standard gives you enough trust and confidence that the data is being exchanged between the App, User and Identity Provider in a secure and transparent manner.&lt;/p&gt;

</description>
      <category>security</category>
      <category>transparency</category>
      <category>openidconnect</category>
      <category>dataprivacy</category>
    </item>
    <item>
      <title>Beyond the login screen - Part I</title>
      <dc:creator>Shyamala</dc:creator>
      <pubDate>Fri, 09 Mar 2018 11:49:15 +0000</pubDate>
      <link>https://forem.com/shyamala_u/beyond-the-login-screen---part-i--29g3</link>
      <guid>https://forem.com/shyamala_u/beyond-the-login-screen---part-i--29g3</guid>
      <description>&lt;p&gt;Recently I came across this tweet,&lt;/p&gt;


&lt;blockquote class="ltag__twitter-tweet"&gt;

  &lt;div class="ltag__twitter-tweet__main"&gt;
    &lt;div class="ltag__twitter-tweet__header"&gt;
      &lt;img class="ltag__twitter-tweet__profile-image" src="https://res.cloudinary.com/practicaldev/image/fetch/s--HdSlcxba--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pbs.twimg.com/profile_images/803507008842256385/7viWqOvs_normal.jpg" alt="██ Oliver █ L██████ profile image"&gt;
      &lt;div class="ltag__twitter-tweet__full-name"&gt;
        ██ Oliver █ L██████
      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__username"&gt;
        @eey0re
      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__twitter-logo"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ir1kO05j--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-f95605061196010f91e64806688390eb1a4dbc9e913682e043eb8b1e06ca484f.svg" alt="twitter logo"&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__body"&gt;
      If you're collecting personal data, "how should I protect this?" is actually your third question.&lt;br&gt;&lt;br&gt;"Should I collect this?" is only the second question.&lt;br&gt;&lt;br&gt;The first question is "what would the worst people do if they got hold of this?"
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__date"&gt;
      03:49 AM - 04 Mar 2018
    &lt;/div&gt;


    &lt;div class="ltag__twitter-tweet__actions"&gt;
      &lt;a href="https://twitter.com/intent/tweet?in_reply_to=970144255745212416" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fFnoeFxk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-reply-action-238fe0a37991706a6880ed13941c3efd6b371e4aefe288fe8e0db85250708bc4.svg" alt="Twitter reply action"&gt;
      &lt;/a&gt;
      &lt;a href="https://twitter.com/intent/retweet?tweet_id=970144255745212416" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--k6dcrOn8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-retweet-action-632c83532a4e7de573c5c08dbb090ee18b348b13e2793175fea914827bc42046.svg" alt="Twitter retweet action"&gt;
      &lt;/a&gt;
      &lt;a href="https://twitter.com/intent/like?tweet_id=970144255745212416" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SRQc9lOp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-like-action-1ea89f4b87c7d37465b0eb78d51fcb7fe6c03a089805d7ea014ba71365be5171.svg" alt="Twitter like action"&gt;
      &lt;/a&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/blockquote&gt;


&lt;p&gt;This tweet got me thinking, Personal data even how trivial it is can be dangerous in the hands of a wrong person. But can we stop collecting data about the user? Can we say with certainty that the system we are building is impenetrable? &lt;/p&gt;

&lt;p&gt;We as part of a product team has responsibility to be transparent to our users about &lt;strong&gt;What&lt;/strong&gt; data of the user our product needs and &lt;strong&gt;Why&lt;/strong&gt; the user has to share it, So the user is conscious of the data being shared and there by implications.&lt;/p&gt;

&lt;p&gt;Let us not be very greedy to ask for all data at once from the user. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--058NFlED--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/izfgmkdmn4w11rtz0ocj.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--058NFlED--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/izfgmkdmn4w11rtz0ocj.gif"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I think we can also apply lean principle in collecting the data from the user, by asking for user's data only when we need them and of course explaining the Whats and Whys.&lt;/p&gt;

&lt;p&gt;We can craft a unique solution for each of our suite of products ourselves or we can abstract away the method of collecting some of the most common user data that we collect in a safe, secure and trusted way. &lt;/p&gt;

&lt;p&gt;There are a number of Open standards for exchanging the authentication and authorization data between users and services/products. Most popular among them are SAML, OAuth2 and OpenId Connect. These standards gives us the trust that a user data is exchanged in a secure manner that is transparent to the user.&lt;/p&gt;

&lt;p&gt;Let us bring a change in thought process that authentication or authorization is not mere a login screen. Let us think about these aspects early in our product design phase.&lt;/p&gt;

&lt;p&gt;So may be it is time for us to think about these Federated Authentication and Authorization standards, that gives users the &lt;strong&gt;right to grant and revoke access to their data&lt;/strong&gt; at any point?&lt;/p&gt;

&lt;p&gt;In the next part , I will go deeper in to one of these Open Standards OpenID Connect..&lt;/p&gt;

</description>
      <category>security</category>
      <category>transparency</category>
      <category>openidconnect</category>
      <category>dataprivacy</category>
    </item>
    <item>
      <title>Hi, I'm Shyamala</title>
      <dc:creator>Shyamala</dc:creator>
      <pubDate>Tue, 14 Mar 2017 08:00:41 +0000</pubDate>
      <link>https://forem.com/shyamala_u/hi-im-shyamala</link>
      <guid>https://forem.com/shyamala_u/hi-im-shyamala</guid>
      <description>&lt;p&gt;I have been coding for 6 years.&lt;/p&gt;

&lt;p&gt;You can find me on Twitter as &lt;a href="https://twitter.com/shyamala_u" rel="noopener noreferrer"&gt;@shyamala_u&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I mostly program in these language: Java.&lt;/p&gt;

&lt;p&gt;I am currently learning more about functional programming &lt;/p&gt;

&lt;p&gt;Nice to meet you.&lt;/p&gt;

</description>
      <category>introduction</category>
    </item>
  </channel>
</rss>
