<?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>DEV Community: Enrico Triolo</title>
    <description>The latest articles on DEV Community by Enrico Triolo (@okrad).</description>
    <link>https://dev.to/okrad</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%2F357762%2F9ab49c72-8852-4845-901a-7e7b36d31f48.png</url>
      <title>DEV Community: Enrico Triolo</title>
      <link>https://dev.to/okrad</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/okrad"/>
    <language>en</language>
    <item>
      <title>Mastering the viewBox for fun and profit</title>
      <dc:creator>Enrico Triolo</dc:creator>
      <pubDate>Fri, 17 Jul 2020 20:05:59 +0000</pubDate>
      <link>https://dev.to/okrad/use-svg-viewbox-as-a-pro-3bd7</link>
      <guid>https://dev.to/okrad/use-svg-viewbox-as-a-pro-3bd7</guid>
      <description>&lt;p&gt;This is the first of a series of articles I'm planning to write about a couple of powerful yet fairly simple concepts of the SVG image format: the &lt;strong&gt;viewport&lt;/strong&gt; and the &lt;strong&gt;viewBox&lt;/strong&gt;.&lt;br&gt;
As I'm going to show you, these are very flexible features: indeed they can be (ab)used to obtain many different effects!&lt;/p&gt;

&lt;p&gt;In this article I will first introduce the SVG image format. Then I will move on to describe the SVG coordinate system and positioning.&lt;/p&gt;

&lt;h1&gt;
  
  
  The SVG format
&lt;/h1&gt;

&lt;p&gt;SVG is a rather peculiar format. Unlike raster formats that describe an image through a grid of pixels, SVG describes an image using &lt;strong&gt;algorithms&lt;/strong&gt; that define the shapes and paths that create the complete image.&lt;/p&gt;

&lt;p&gt;SVG isn't suited to represent photographic images, but is particularly suited to draw &lt;strong&gt;illustrations and icons&lt;/strong&gt; in a &lt;strong&gt;compact way&lt;/strong&gt;. An SVG image is basically composed of one or more "shapes", each described by a specific mathematical function. Thanks to this, an SVG image can be enlarged/zoomed as much as you want, unlike the raster image formats.&lt;/p&gt;

&lt;p&gt;Another difference with the bitmap formats is that SVG is a &lt;strong&gt;human-readable&lt;/strong&gt; text format. In fact an SVG image is nothing more than an XML document. Each shape can be defined using simple textual instructions in the form of XML nodes.&lt;/p&gt;

&lt;p&gt;For example, this markup creates an image with a blue circle:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;

&lt;span class="nt"&gt;&amp;lt;svg&lt;/span&gt; &lt;span class="na"&gt;xmlns=&lt;/span&gt;&lt;span class="s"&gt;"http://www.w3.org/2000/svg"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;circle&lt;/span&gt; &lt;span class="na"&gt;cx=&lt;/span&gt;&lt;span class="s"&gt;"50"&lt;/span&gt; &lt;span class="na"&gt;cy=&lt;/span&gt;&lt;span class="s"&gt;"50"&lt;/span&gt; &lt;span class="na"&gt;r=&lt;/span&gt;&lt;span class="s"&gt;"50"&lt;/span&gt; &lt;span class="na"&gt;fill=&lt;/span&gt;&lt;span class="s"&gt;"#0971f1"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/svg&amp;gt;&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;The SVG specification defines many other tags that can be used to create both basic and complex shapes, such as rectangles, arcs, ellipses, or "paths", that can be used to define custom shapes using so called "Bezier curves".&lt;/p&gt;

&lt;p&gt;Another great feature of the SVG file format, especially when used inside a web page, is that it can be &lt;strong&gt;styled&lt;/strong&gt; in many ways through dedicated &lt;strong&gt;css&lt;/strong&gt; properties or through so called "presentation attributes", i.e. CSS properties that can be used as attributes on SVG elements.&lt;/p&gt;

&lt;p&gt;For example, you can change the color of a shape by simply setting the "fill" property.&lt;/p&gt;

&lt;p&gt;In the previous example, we indeed defined the color of the circle using the "fill" attribute. Another way would be to assign the circle node a class, and then defining the style rules for that class in a css file:&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;

&lt;p&gt;&lt;span class="nt"&gt;&amp;lt;svg&lt;/span&gt; &lt;span class="na"&gt;xmlns=&lt;/span&gt;&lt;span class="s"&gt;"&lt;a href="http://www.w3.org/2000/svg" rel="noopener noreferrer"&gt;http://www.w3.org/2000/svg&lt;/a&gt;"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;&lt;br&gt;
    &lt;span class="nt"&gt;&amp;lt;circle&lt;/span&gt; &lt;span class="na"&gt;cx=&lt;/span&gt;&lt;span class="s"&gt;"50"&lt;/span&gt; &lt;span class="na"&gt;cy=&lt;/span&gt;&lt;span class="s"&gt;"50"&lt;/span&gt; &lt;span class="na"&gt;r=&lt;/span&gt;&lt;span class="s"&gt;"50"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"mycircle"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;&lt;br&gt;
&lt;span class="nt"&gt;&amp;lt;/svg&amp;gt;&lt;/span&gt;&lt;/p&gt;

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

&lt;/div&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;

&lt;p&gt;&lt;span class="nc"&gt;.mycircle&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;br&gt;
    &lt;span class="py"&gt;fill&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#0971f1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;br&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;/p&gt;

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

&lt;/div&gt;
&lt;h2&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  The viewport and the viewBox&lt;br&gt;
&lt;/h2&gt;

&lt;p&gt;The &lt;em&gt;viewport&lt;/em&gt; and the &lt;em&gt;viewBox&lt;/em&gt; are two very important concepts that affect the size, the position and the visible area of an SVG image.&lt;/p&gt;

&lt;p&gt;You can effectively think of the &lt;strong&gt;viewport&lt;/strong&gt; as your mobile phone &lt;strong&gt;display&lt;/strong&gt; with the camera app running.&lt;br&gt;
The &lt;strong&gt;viewBox&lt;/strong&gt; is the &lt;strong&gt;part&lt;/strong&gt; of the &lt;strong&gt;scene&lt;/strong&gt; you see inside the display. You can zoom in and out or move the phone and frame different parts of the scene, so to change the viewBox, but it will always be constrained to the physical size of the display, i.e. the viewport.&lt;br&gt;
Lastly, the whole scene represent your SVG image, the so called &lt;strong&gt;SVG canvas&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fokrad%2Fviewbox-article%2Fraw%2Fmaster%2Fimg%2Fviewbox_example.png%3Fv%3D1" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fokrad%2Fviewbox-article%2Fraw%2Fmaster%2Fimg%2Fviewbox_example.png%3Fv%3D1" alt="SVG viewport and viewBox example"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Inside an SVG document, all measures are unitless: you don't say "this rectangle is 10mm large", you just say "this rectangle is large 10".&lt;br&gt;
In our first example, we are just saying that the circle has its center at (50, 50) (not 50 &lt;em&gt;px&lt;/em&gt; or &lt;em&gt;mm&lt;/em&gt;) and that its radius is just "50" (and not 50 &lt;em&gt;px&lt;/em&gt;). These dimensions are called &lt;em&gt;user units&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;viewport&lt;/strong&gt; can be set using two attributes on the SVG element: &lt;strong&gt;width&lt;/strong&gt; and &lt;strong&gt;height&lt;/strong&gt;. These represent the width and the height of the "display".&lt;br&gt;
The viewport is specified using one of the units of measure that are known to the user agent: the browser in fact needs to know how much space to reserve in the DOM for the image.&lt;br&gt;
When the viewport is specified in user units, the values are assumed to be in "px".&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;viewBox&lt;/strong&gt; controls which &lt;strong&gt;part&lt;/strong&gt; of the image will be &lt;strong&gt;shown&lt;/strong&gt; and at which &lt;strong&gt;size&lt;/strong&gt;. It is defined using the &lt;em&gt;viewBox&lt;/em&gt; attribute on the root SVG element, and its value is a space (or comma) separated list of 4 numbers expressed in user units that describe a rectangle that will be mapped to the size of the viewport. The four numbers represent respectively:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;min-x&lt;/strong&gt;: the horizontal coordinate of the upper left corner of the rectangle.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;min-y&lt;/strong&gt;: the vertical coordinate of the upper left corner of the rectangle&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;width&lt;/strong&gt;: the width of the rectangle...&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;height&lt;/strong&gt;: you guessed it!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When not specified, the viewBox is assumed to correspond to the SVG canvas.&lt;/p&gt;

&lt;h2&gt;
  
  
  Some examples
&lt;/h2&gt;

&lt;p&gt;In the following example we are mapping the full SVG canvas to the viewport.&lt;br&gt;
As you can see, the canvas size is 200 x 200, while the viewport size is 50px x 50px. Since the viewBox area has its top-left corner at (0,0), width and height both equal to 200 (which are the same sizes of the canvas), all the image is rendered inside the viewport:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fokrad%2Fviewbox-article%2Fraw%2Fmaster%2Fimg%2Fviewbox_mapping1.png%3Fv%3D4" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fokrad%2Fviewbox-article%2Fraw%2Fmaster%2Fimg%2Fviewbox_mapping1.png%3Fv%3D4" alt="Mapping the full canvas to the viewport"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;In the next example, the viewBox size is 100 x 100, which corresponds to half of the canvas size. Since the top-left corner of the viewBox is set to (0,0), the viewport will show only the top-left quarter of the image:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fokrad%2Fviewbox-article%2Fraw%2Fmaster%2Fimg%2Fviewbox_mapping2.png%3Fv%3D4" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fokrad%2Fviewbox-article%2Fraw%2Fmaster%2Fimg%2Fviewbox_mapping2.png%3Fv%3D4" alt="Mapping part of the svg canvas to the viewport"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;This time the viewBox rectangle has its top-left corner right in the middle of the canvas. The width and height of the viewBox are both 100... What we get to see in the viewport is therefore the bottom-right part of the svg:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fokrad%2Fviewbox-article%2Fraw%2Fmaster%2Fimg%2Fviewbox_mapping3.png%3Fv%3D4" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fokrad%2Fviewbox-article%2Fraw%2Fmaster%2Fimg%2Fviewbox_mapping3.png%3Fv%3D4" alt="Mapping part of the svg canvas to the viewport"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The preserveAspectRatio attribute
&lt;/h2&gt;

&lt;p&gt;The examples seen till now all have one thing in common: the viewBox has the same aspect ratio of the viewport, i.e. the ratio between the viewBox width and height is the same ratio between the viewport width and height.&lt;/p&gt;

&lt;p&gt;But what happens when the viewBox aspect ratio differs from that of the viewport? The &lt;strong&gt;preserveAspectRatio&lt;/strong&gt; attribute controls just this behaviour. Its value is made up of two keywords: the &lt;em&gt;alignment value&lt;/em&gt; and the &lt;em&gt;meet or slice reference&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;alignment value&lt;/strong&gt; determines how the image should be scaled. It can take up to 10 values, the most straightforward of them being:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;none&lt;/strong&gt;: in this case the image will be scaled &lt;strong&gt;non uniformely&lt;/strong&gt; to completeley fit into the viewport without taking into account its aspect ratio.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fokrad%2Fviewbox-article%2Fraw%2Fmaster%2Fimg%2Fviewbox_mapping4.png%3Fv%3D5" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fokrad%2Fviewbox-article%2Fraw%2Fmaster%2Fimg%2Fviewbox_mapping4.png%3Fv%3D5" alt="Scaling the viewBox non uniformely to fit into a viewport with different aspect ratio"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In all the following cases the image is instead &lt;strong&gt;uniformely scaled&lt;/strong&gt;. These values determine where to position the scaled viewBox with respect to the viewport:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;xMinYMin&lt;/strong&gt;: the min-x and min-y values of the viewBox (the first two numbers) are aligned to the upper left corner of the viewport.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;xMidYMin&lt;/strong&gt;: the horizontal center of the viewBox is aligned with the horizontal center of the viewport while the min-y of the viewBox is aligned with the top of the viewport.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;xMaxYMin&lt;/strong&gt;: the min-x + width of the viewBox (i.e. the "right side") is aligned with the right of the viewport while the min-y of the viewBox is aligned with the top of the viewport.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;xMinYMid&lt;/strong&gt;: the min-x of the viewBox is aligned with the left of the viewport while the vertical center of the vieBox is aligned with the vertical center of the viewport.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;xMidYMid&lt;/strong&gt;: the horizontal and vertical centers of the viewBox are aligned with the center point of viewport.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;xMaxYMid&lt;/strong&gt;: the min-x + width of the viewBox (the "right side") is aligned with the right of the viewport while the vertical center of the viewBox is aligned with the vertical center of the viewport.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;xMinYMax&lt;/strong&gt;: the min-x of the viewBox is aligned with the left of the viewport while the min-y + height of the viewBox (the "bottom side") is aligned with the bottom of the viewport.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;xMidYMax&lt;/strong&gt;: the horizontal center of the viewBox is aligned with the horizontal center of the viewport while the min-y + height of the viewBox (the "bottom side") is aligned with the bottom of the viewport.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;xMaxYMax&lt;/strong&gt;: the min-x + width of the viewBox (the "right side") is aligned with the right of the viewport while the min-y + height of the viewBox (the "bottom side") is aligned with the bottom of the viewport.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The second keyword of the &lt;em&gt;preserveAspectRatio&lt;/em&gt; atttibute (the &lt;strong&gt;meet or slice reference&lt;/strong&gt;) is optional and determines how the image should be scaled. It can be one of the two following values:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;meet&lt;/strong&gt;: the default value. The image is scaled such that the &lt;strong&gt;viewBox entirely fits&lt;/strong&gt; into the viewport while preserving its aspect ratio. This means that the viewBox could result smaller than the viewport, depending on their aspect ratios.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fokrad%2Fviewbox-article%2Fraw%2Fmaster%2Fimg%2Fviewbox_mapping_xymeet.png%3Fv%3D4" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fokrad%2Fviewbox-article%2Fraw%2Fmaster%2Fimg%2Fviewbox_mapping_xymeet.png%3Fv%3D4" alt="Mapping viewBox to a viewport with different aspect ratio, keeping aspect ratio (meet)"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;slice&lt;/strong&gt;: The image is scaled such that the &lt;strong&gt;viewBox covers the viewport&lt;/strong&gt; while preserving its aspect ratio. This means that the viewBox could extend beyond the viewport, depending on their aspect ratios.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fokrad%2Fviewbox-article%2Fraw%2Fmaster%2Fimg%2Fviewbox_mapping_xyslice.png%3Fv%3D4" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fokrad%2Fviewbox-article%2Fraw%2Fmaster%2Fimg%2Fviewbox_mapping_xyslice.png%3Fv%3D4" alt="Mapping viewBox to a viewport with different aspect ratio, keeping aspect ratio (slice)"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  That's all for now!
&lt;/h2&gt;

&lt;p&gt;Now that we introduced the base concepts we can go on and see how just by changing the numbers of the viewBox we can achieve different "tricks". In the next articles of this serie we are just going to see some of them!&lt;/p&gt;

&lt;h3&gt;
  
  
  References
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/viewBox" rel="noopener noreferrer"&gt;Mozilla article&lt;/a&gt; on the viewBox&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.sarasoueidan.com/blog/svg-coordinate-systems/" rel="noopener noreferrer"&gt;Understanding SVG Coordinate Systems and Transformations (Part 1) — The viewport, viewBox, and preserveAspectRatio&lt;/a&gt; by &lt;a href="https://www.sarasoueidan.com" rel="noopener noreferrer"&gt;Sara Soueidan&lt;/a&gt; - Btw, you should definitely follow her!&lt;/li&gt;
&lt;li&gt;Cover photo by &lt;a href="https://unsplash.com/photos/3_Xwxya43hE" rel="noopener noreferrer"&gt;Pine Watt&lt;/a&gt; on &lt;a href="https://unsplash.com" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>svg</category>
      <category>tutorial</category>
      <category>webdev</category>
    </item>
    <item>
      <title>oauth2_client: implement OAuth2 clients with Flutter</title>
      <dc:creator>Enrico Triolo</dc:creator>
      <pubDate>Mon, 06 Apr 2020 21:33:47 +0000</pubDate>
      <link>https://dev.to/okrad/oauth2client-implement-oauth2-clients-with-flutter-4jjl</link>
      <guid>https://dev.to/okrad/oauth2client-implement-oauth2-clients-with-flutter-4jjl</guid>
      <description>&lt;p&gt;In the first part of this article I will give you an overview of the OAuth 2 standard, in particular I will introduce the two most used grants, the Client Credentials and the Authorization Code grants.&lt;br&gt;
In the second part I will introduce oauth2_client, a Flutter library that considerably simplifies working with OAuth 2.&lt;br&gt;
By the end of the article you will be able to implement your own client with just little lines of code.&lt;/p&gt;

&lt;p&gt;If you are already familiar with the concepts behind OAuth2, you can directly skip to the hands on section, otherwise keep reading...&lt;/p&gt;

&lt;h3&gt;
  
  
  What is OAuth 2?
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://oauth.net/2/" rel="noopener noreferrer"&gt;OAuth 2&lt;/a&gt; is an open standard protocol that allows applications to access  protected resources of a service on behalf of the user. OAuth 2 defines authorization flows for native apps, web apps and for mobile devices.&lt;/p&gt;

&lt;p&gt;Many companies offer OAuth 2 endpoints: these include the &lt;em&gt;usual suspects&lt;/em&gt;, such as Google, Facebook, LinkedIn, GitHub, as well as many other.&lt;/p&gt;

&lt;p&gt;Generally speaking, an authorization process can be carried on as follow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The application sends to the authorization server an Authorization Request to access a protected resource&lt;/li&gt;
&lt;li&gt;The owner of the resource (usually, the user) grants access to it&lt;/li&gt;
&lt;li&gt;The authorization server sends back an Access Token to be used with all the subsequent requests as a sort of authorization badge&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is just an high level depiction of the whole process. The actual flow will differ depending on the authorization grant type in use.&lt;/p&gt;

&lt;p&gt;The two most used grant types are the &lt;a href="https://www.oauth.com/oauth2-servers/access-tokens/client-credentials/" rel="noopener noreferrer"&gt;Client Credentials&lt;/a&gt; grant and the &lt;a href="https://www.oauth.com/oauth2-servers/access-tokens/authorization-code-request/" rel="noopener noreferrer"&gt;Authorization Code&lt;/a&gt; grant.&lt;/p&gt;

&lt;h4&gt;
  
  
  The Client Credentials grant
&lt;/h4&gt;

&lt;p&gt;The &lt;em&gt;Client Credentials&lt;/em&gt; grant is primarily used on machine-to-machine applications, such as daemons, services or CLI. In this case the authorization server grants access to the application itself rather than to the user.&lt;/p&gt;

&lt;p&gt;To use this flow, an application must have been assigned a &lt;em&gt;client ID&lt;/em&gt; and a &lt;em&gt;client secret&lt;/em&gt;. These parameters are generated by the authorization server, and are needed to ensure that the client connecting is the one that has been authorized.&lt;/p&gt;

&lt;p&gt;The authorization process works more or less like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The application sends to the authorization server an Authorization Request along with the &lt;em&gt;client id&lt;/em&gt; and the &lt;em&gt;client secret&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;The authorization server checks the provided credentials&lt;/li&gt;
&lt;li&gt;The authorization server sends back to the application an &lt;em&gt;Access Token&lt;/em&gt;, along with a &lt;em&gt;Referesh Token&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;The application uses the &lt;em&gt;Access Token&lt;/em&gt; in every subsequent request to the service.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.teranet.it%2Fimg%2Farticoli%2Fclient_credentials_grant.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.teranet.it%2Fimg%2Farticoli%2Fclient_credentials_grant.png" alt="Client Credentials grant"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  The Authorization Code grant
&lt;/h4&gt;

&lt;p&gt;The &lt;em&gt;Authorization Code&lt;/em&gt; grant is by far the most used flow as it is employed by applications that effectively operate on some user owned resources.&lt;/p&gt;

&lt;p&gt;To use this flow, the application must have been registered with the OAuth server, providing at least a name and a &lt;em&gt;redirect URI&lt;/em&gt;, that will be used to inform the application that the user authorized the request. During the registration, the provider assigns the application a &lt;em&gt;client ID&lt;/em&gt; and a &lt;em&gt;client secret&lt;/em&gt;, that will be exchanged in the authorization process.&lt;/p&gt;

&lt;p&gt;To access a specific resource, the application should specify one or more &lt;em&gt;scopes&lt;/em&gt;, a list of strings that represent the "permissions" the application is requiring. The scopes are defined by the resource server and are normally included in the API documentation of the service.&lt;/p&gt;

&lt;p&gt;This flow can be summarized like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The user opens up the app&lt;/li&gt;
&lt;li&gt;The app opens up a browser instance pointing to the authorization endpoint on the authorization server, requiring permission to access the needed resources, and passing in the Client ID and the list of required scopes.&lt;/li&gt;
&lt;li&gt;The user authenticates with the authorization server and grants access to the resources&lt;/li&gt;
&lt;li&gt;The authorization server redirects the client to the &lt;em&gt;redirect uri&lt;/em&gt; sending an &lt;em&gt;Authorization Token&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;The client app issues an &lt;em&gt;Access Token Request&lt;/em&gt;, passing in the Authorization Token and the client secret.&lt;/li&gt;
&lt;li&gt;The server validates the client secret and the Authorization Token and sends back an &lt;em&gt;Access Token&lt;/em&gt; and a &lt;em&gt;Refresh Token&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;The client app uses the &lt;em&gt;Access Token&lt;/em&gt; in every subsequent request to the API service as a sort of authorization badge.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.teranet.it%2Fimg%2Farticoli%2Fauthorization_code_grant.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.teranet.it%2Fimg%2Farticoli%2Fauthorization_code_grant.png" alt="Authorization Code grant"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The OAuth 2 framework has been designed to be extensible, and as such it underwent some additions since its inception, for example to address potential security flaws or extend its functionalities. One of these is the &lt;a href="https://oauth.net/2/pkce/" rel="noopener noreferrer"&gt;PKCE&lt;/a&gt; extension, designed to increase the Authorization Code grant security through an exchange of a client generated code that limits the chances of the authorization code to be intercepted.&lt;/p&gt;

&lt;h4&gt;
  
  
  Access Token expiration / invalidation
&lt;/h4&gt;

&lt;p&gt;To limit the risks of token hijacking, the Access Token often has a limited lifespan after which it cannot be used anymore. Moreover, the Access Token could be explicitly invalidated by the resource server.&lt;/p&gt;

&lt;p&gt;When the token expires, the application must require another Access Token using another grant type, the &lt;em&gt;Refresh Token&lt;/em&gt; grant. As the name suggests, this flow uses the &lt;em&gt;Refresh Token&lt;/em&gt; returned by the previous authorization flows to generate a new Access Token that must be used from that moment onward.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hands on! &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;By now it should be clear that to implement an OAuth 2 capable application, one must implement not only the authorization process provided by the service he is going to use, but even the mechanisms to deal with the expiration or invalidation of the Access Token. These can easily become quite wasteful activities!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://pub.dev/packages/oauth2_client" rel="noopener noreferrer"&gt;oauth2_client&lt;/a&gt; is a Flutter library specifically created with the purpose of simplifying the process of requiring and refreshing the OAuth 2 access token. It provides pre-made classes to authenticate againts the leading providers, such as Google, Facebook, LinkedIn, GitHub, but it's particularly suited for implementing clients for custom OAuth 2 servers.&lt;/p&gt;

&lt;p&gt;It additionally provides convenience methods for secure token storage, automatic token refreshing and to transparently perform authenticated HTTP requests.&lt;/p&gt;

&lt;p&gt;Suppose we wanted to implement an app with the GitHub API. As per their &lt;a href="https://developer.github.com/apps/building-oauth-apps/authorizing-oauth-apps/" rel="noopener noreferrer"&gt;API documentation&lt;/a&gt;, GitHub  recommends on using the Web application flow (with the &lt;em&gt;Authorization Code&lt;/em&gt; grant).&lt;br&gt;
This means that one of the steps of the process involves opening up a browser instance and intercepting a redirection to a provided redirect uri.&lt;/p&gt;

&lt;p&gt;If one of the targets of our app is Android, we first need to set up an Intent Filter in the AndroidManifest.xml file to define a custom uri scheme that will be intercepted by our app:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;

&lt;span class="nt"&gt;&amp;lt;manifest&lt;/span&gt; &lt;span class="na"&gt;xmlns:android=&lt;/span&gt;&lt;span class="s"&gt;"http://schemas.android.com/apk/res/android"&lt;/span&gt;
    &lt;span class="na"&gt;package=&lt;/span&gt;&lt;span class="s"&gt;"com.example.mypackage"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    ...
    &lt;span class="nt"&gt;&amp;lt;activity&lt;/span&gt; &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;"com.linusu.flutter_web_auth.CallbackActivity"&lt;/span&gt; &lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;intent-filter&lt;/span&gt; &lt;span class="na"&gt;android:label=&lt;/span&gt;&lt;span class="s"&gt;"flutter_web_auth"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;action&lt;/span&gt; &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;"android.intent.action.VIEW"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;category&lt;/span&gt; &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;"android.intent.category.DEFAULT"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;category&lt;/span&gt; &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;"android.intent.category.BROWSABLE"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;data&lt;/span&gt; &lt;span class="na"&gt;android:scheme=&lt;/span&gt;&lt;span class="s"&gt;"my.app"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/intent-filter&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/activity&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/manifest&amp;gt;&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;The value of the &lt;em&gt;android:scheme&lt;/em&gt; attribute can be anything you want, and must match the scheme used for the redirect uri (as we'll see later). Just make sure, if at all possible, &lt;strong&gt;not to use http(s)&lt;/strong&gt;, because in that case our application won't be able to intercept the server redirection, as it will be automatically handled by the system browser.&lt;/p&gt;

&lt;p&gt;If you really want/need to &lt;strong&gt;use&lt;/strong&gt; an &lt;strong&gt;HTTPS&lt;/strong&gt; url as the redirect uri, you must setup it as an &lt;a href="https://developer.android.com/training/app-links/index.html" rel="noopener noreferrer"&gt;App Link&lt;/a&gt;.&lt;br&gt;
First you need to specify both the android:host and android:pathPrefix attributes, as long as the &lt;em&gt;android:autoVerify="true"&lt;/em&gt; attribute on the intent-filter tag:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;

&lt;span class="nt"&gt;&amp;lt;activity&lt;/span&gt; &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;"com.linusu.flutter_web_auth.CallbackActivity"&lt;/span&gt; &lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;intent-filter&lt;/span&gt; &lt;span class="na"&gt;android:label=&lt;/span&gt;&lt;span class="s"&gt;"flutter_web_auth"&lt;/span&gt; &lt;span class="na"&gt;android:autoVerify=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;action&lt;/span&gt; &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;"android.intent.action.VIEW"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;category&lt;/span&gt; &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;"android.intent.category.DEFAULT"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;category&lt;/span&gt; &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;"android.intent.category.BROWSABLE"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

        &lt;span class="nt"&gt;&amp;lt;data&lt;/span&gt; &lt;span class="na"&gt;android:scheme=&lt;/span&gt;&lt;span class="s"&gt;"https"&lt;/span&gt;
                &lt;span class="na"&gt;android:host=&lt;/span&gt;&lt;span class="s"&gt;"www.myapp.com"&lt;/span&gt;
                &lt;span class="na"&gt;android:pathPrefix=&lt;/span&gt;&lt;span class="s"&gt;"/oauth2redirect"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/intent-filter&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/activity&amp;gt;&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Then you need to &lt;a href="https://developer.android.com/training/app-links/verify-site-associations" rel="noopener noreferrer"&gt;prove ownership&lt;/a&gt; of the domain host by publishing a &lt;a href="https://developers.google.com/digital-asset-links/v1/getting-started" rel="noopener noreferrer"&gt;Digital Asset Links&lt;/a&gt; JSON file on your website. This involves generating an &lt;a href="https://developer.android.com/studio/publish/app-signing" rel="noopener noreferrer"&gt;App signing key&lt;/a&gt; and signing your app with it. &lt;/p&gt;

&lt;p&gt;Our sample app will retrieve the list of the user's repositories. To do so, we must tell the server which "permissions" we'll need, using the &lt;em&gt;scope&lt;/em&gt; parameter. The scope that requires access to the user's repositories (both public and private)  is "repo".&lt;/p&gt;

&lt;p&gt;Before you can interact with GitHub's OAuth 2 endpoint, you must &lt;a href="https://developer.github.com/apps/building-oauth-apps/creating-an-oauth-app/" rel="noopener noreferrer"&gt;create a new OAuth App&lt;/a&gt;. After this step your application will be assigned a &lt;em&gt;clientId&lt;/em&gt; and a &lt;em&gt;clientSecret&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Ok, enough of talking... Let's see some code!&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:oauth2_client/github_oauth2_client.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:oauth2_client/access_token_response.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;//Instantiate the GitHub client&lt;/span&gt;
&lt;span class="n"&gt;OAuth2Client&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;GitHubOAuth2Client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="c1"&gt;//Corresponds to the android:scheme attribute&lt;/span&gt;
    &lt;span class="nl"&gt;customUriScheme:&lt;/span&gt; &lt;span class="s"&gt;'my.app'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="c1"&gt;//The scheme must match the customUriScheme parameter!&lt;/span&gt;
    &lt;span class="nl"&gt;redirectUri:&lt;/span&gt; &lt;span class="s"&gt;'my.app://oauth2redirect'&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;//Require an Access Token with the Authorization Code grant&lt;/span&gt;
&lt;span class="n"&gt;AccessTokenResponse&lt;/span&gt; &lt;span class="n"&gt;tknResp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getTokenWithAuthCodeFlow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nl"&gt;clientId:&lt;/span&gt; &lt;span class="s"&gt;'myclientid'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nl"&gt;clientSecret:&lt;/span&gt; &lt;span class="s"&gt;'myclientsecret'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nl"&gt;scopes:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'repo'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

&lt;span class="c1"&gt;//From now on you can perform authenticated HTTP requests&lt;/span&gt;
&lt;span class="n"&gt;httpClient&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="na"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Response&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;httpClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'https://api.github.com/user/repos'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nl"&gt;headers:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;'Authorization'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;'Bearer '&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;tknResp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;accessToken&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;//The list of the user repositories is encoded in the resp.body property...&lt;/span&gt;



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

&lt;/div&gt;

&lt;p&gt;As you see, fetching an Access Token is quite simple, and since GitHub tokens don't expire we should be all set... But what happens if the token gets invalidated by the app owner? You would need to check the validity of the token after every request and possibly fetch another token. Something like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;

&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="n"&gt;httpClient&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="na"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Response&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;httpClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'https://api.github.com/user/repos'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nl"&gt;headers:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;'Authorization'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;'Bearer '&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;tknResp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;accessToken&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;//The request to the service didn't succeed...&lt;/span&gt;
&lt;span class="c1"&gt;//We must refresh the token (not supported by GitHub endpoint) or&lt;/span&gt;
&lt;span class="c1"&gt;//generate a new Access Token&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;resp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;statusCode&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;AccessTokenResponse&lt;/span&gt; &lt;span class="n"&gt;tknResp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getTokenWithAuthCodeFlow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nl"&gt;clientId:&lt;/span&gt; &lt;span class="s"&gt;'myclientid'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nl"&gt;clientSecret:&lt;/span&gt; &lt;span class="s"&gt;'myclientsecret'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nl"&gt;scopes:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'repo'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

    &lt;span class="c1"&gt;//Perform another request to the server with the new access token&lt;/span&gt;
    &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Response&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;httpClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'https://api.github.com/user/repos'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nl"&gt;headers:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;'Authorization'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;'Bearer '&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;tknResp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;accessToken&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;Fortunately enough, the library provides an helper class that takes care of all of the burden:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;

&lt;span class="c1"&gt;//Instantiate the client...&lt;/span&gt;
&lt;span class="n"&gt;OAuth2Client&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;GitHubOAuth2Client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nl"&gt;redirectUri:&lt;/span&gt; &lt;span class="s"&gt;'my.app://oauth2redirect'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nl"&gt;customUriScheme:&lt;/span&gt; &lt;span class="s"&gt;'my.app'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;//Instantiate the helper passing it the client and passing in the authorization parameters&lt;/span&gt;
&lt;span class="n"&gt;OAuth2Helper&lt;/span&gt; &lt;span class="n"&gt;oauth2Helper&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;OAuth2Helper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nl"&gt;grantType:&lt;/span&gt; &lt;span class="n"&gt;OAuth2Helper&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;AUTHORIZATION_CODE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;//default value, can be omitted&lt;/span&gt;
    &lt;span class="nl"&gt;clientId:&lt;/span&gt; &lt;span class="s"&gt;'myclientid'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nl"&gt;clientSecret:&lt;/span&gt; &lt;span class="s"&gt;'myclientsecret'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nl"&gt;scopes:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'repo'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

&lt;span class="c1"&gt;//Perform a request to the server&lt;/span&gt;
&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Response&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;oauth2Helper&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'https://api.github.com/user/repos'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;As long as the first request is made, the helper class performs the following operations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Checks if an Access Token already exists in the device storage&lt;/li&gt;
&lt;li&gt;If it doesn't exist, generates an Access Token using the required flow (Authorization Code when not specified) and stores it into the device secure storage.&lt;/li&gt;
&lt;li&gt;Sends the request to the server, adding the "Authorization" header with the access token&lt;/li&gt;
&lt;li&gt;If the server returns an "unauthorized" response, try to refresh the Access Token through the Refresh Token flow, if the service supports it, otherwise generate a new token. Finally, send another request with the new token.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As you see, not only the helper class takes care of the token retrieval/refresh process, it even stores the token in a secure storage on the device. This means that if your app is closed or the device is restarted, the retrieved tokens are still available and can be used without requiring a new authorization process.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;em&gt;That's all well and good, but what if I wanted to implement my own client?&lt;/em&gt;
&lt;/h3&gt;

&lt;p&gt;Up until now, we saw how to use a predefined client class, but what if you needed to authenticate against a service that doesn't have a dedicated class?&lt;/p&gt;

&lt;p&gt;Implementing your own clients is really simple, and normally requires only a couple of lines of code. For example, let's see how the GitHub client is made:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;GitHubOAuth2Client&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;OAuth2Client&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;GitHubOAuth2Client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nd"&gt;@required&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;redirectUri&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nd"&gt;@required&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;customUriScheme&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nl"&gt;authorizeUrl:&lt;/span&gt; &lt;span class="s"&gt;'https://github.com/login/oauth/authorize'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nl"&gt;tokenUrl:&lt;/span&gt; &lt;span class="s"&gt;'https://github.com/login/oauth/access_token'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nl"&gt;redirectUri:&lt;/span&gt; &lt;span class="n"&gt;redirectUri&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nl"&gt;customUriScheme:&lt;/span&gt; &lt;span class="n"&gt;customUriScheme&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

      &lt;span class="c1"&gt;//By default, GitHub responds to an Access Token request with a querystring-like&lt;/span&gt;
      &lt;span class="c1"&gt;//format. We need a json formatted response, that can be required through&lt;/span&gt;
      &lt;span class="c1"&gt;//the 'Accept' header...&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;accessTokenRequestHeaders&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="s"&gt;'Accept'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;'application/json'&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;That's it! You really just need to extend the OAuth2Client class and provide the authorization and the token urls.&lt;br&gt;
After that, you can use your client or even the helper as seen above, without any modifications.&lt;/p&gt;

&lt;h2&gt;
  
  
  Finally... The inevitable TL;DR
&lt;/h2&gt;

&lt;p&gt;oauth2_client really simplifies working with OAuth 2 endpoints, as it takes care of all the peculiarities of the protocol and automates the process of refreshing the tokens upon expiration. It even transparently implements many of the best practices introduced to enforce the security and reliability of the process.&lt;/p&gt;

</description>
      <category>oauth</category>
      <category>oauth2</category>
      <category>flutter</category>
      <category>dart</category>
    </item>
  </channel>
</rss>
