<?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: Pier</title>
    <description>The latest articles on DEV Community by Pier (@rampi).</description>
    <link>https://dev.to/rampi</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%2F13070%2F5caa4703-7521-48bc-a11e-4bc73a4e69dd.png</url>
      <title>DEV Community: Pier</title>
      <link>https://dev.to/rampi</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/rampi"/>
    <language>en</language>
    <item>
      <title>OAuth2 authentication for a Google Cloud Functions</title>
      <dc:creator>Pier</dc:creator>
      <pubDate>Sat, 26 Feb 2022 20:00:36 +0000</pubDate>
      <link>https://dev.to/rampi/oauth2-authentication-for-a-google-cloud-functions-56g</link>
      <guid>https://dev.to/rampi/oauth2-authentication-for-a-google-cloud-functions-56g</guid>
      <description>&lt;h2&gt;
  
  
  What is Google Cloud Functions?
&lt;/h2&gt;

&lt;p&gt;Cloud Functions is the go-to tool for FaaS (functions as a service) on Google Cloud. It has a very intuitive interface for creating functions in few minutes!&lt;br&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwx936fl02uvzt2ig0tnf.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwx936fl02uvzt2ig0tnf.png" alt="Auth options"&gt;&lt;/a&gt;&lt;br&gt;
Cloud Functions supports IAM authentication but can I authenticate the service using an OAuth2 provider?&lt;/p&gt;

&lt;h2&gt;
  
  
  How does it work?
&lt;/h2&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwwbhb6xas475inxockqm.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwwbhb6xas475inxockqm.png" alt="Auth Flow"&gt;&lt;/a&gt;&lt;br&gt;
In the first step we retrieve the token from an OAuth2 provider (I used Keycloak but you could use another one), then we call the function through the Google API Gateway. The API Gateway supports OpenAPI2 configuration, where we need to setup the authentication. In the final step the API Gateway calls, using a service account, the Cloud Function.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create the Cloud Function
&lt;/h2&gt;

&lt;p&gt;Here we can see how to create a cloud function using gcloud command line, but the same can be achieved using the Google Cloud web interface.&lt;/p&gt;

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

git clone https://github.com/GoogleCloudPlatform/nodejs-docs-samples.git
cd nodejs-docs-samples/functions/helloworld/
# CREATE FUNCTION
gcloud functions deploy helloGET --runtime nodejs16 --trigger-http


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

&lt;/div&gt;

&lt;p&gt;The last command asks if we want to allow unauthenticated invocations for the new function, which we don’t, so we say no.&lt;/p&gt;

&lt;p&gt;This creates a cloud function with IAM authentication and with an http trigger.&lt;br&gt;&lt;br&gt;
We need to create a GCP Service Account with the Cloud Function Invoker role, we use it later.&lt;/p&gt;

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

# CREATE SERVICE ACCOUNT
gcloud iam service-accounts create function-invoker --display-name="function-invoker"
# BINDING ROLES
gcloud projects add-iam-policy-binding my-project --member="serviceAccount:function-invoker@my-project.iam.gserviceaccount.com" --role="roles/cloudfunctions.invoker"


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

&lt;/div&gt;
&lt;h2&gt;
  
  
  API Gateway setup
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Enable APIs
&lt;/h3&gt;

&lt;p&gt;To use API Gateway we need to enable services.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

gcloud services enable apigateway.googleapis.com
gcloud services enable servicemanagement.googleapis.com
gcloud services enable servicecontrol.googleapis.com


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

&lt;/div&gt;
&lt;h3&gt;
  
  
  Create the API Config
&lt;/h3&gt;

&lt;p&gt;API Gateway supports the OpenAPI spec. Here we need to define the right security configuration! In order to fill the correct information in this file we need to have the cloud function http trigger (&lt;code&gt;x-google-backend&lt;/code&gt;) and the right security information (&lt;a href="https://cloud.google.com/endpoints/docs/openapi/openapi-extensions" rel="noopener noreferrer"&gt;openapi-extensions&lt;/a&gt;).&lt;br&gt;&lt;br&gt;
An example below:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

# openapi2-functions.yaml
swagger: '2.0'
info:
  title: hello
  description: Sample API on API Gateway with a Google Cloud Functions backend
  version: 1.0.0
schemes:
  - https
produces:
  - application/json
paths:
  /hello:
    get:
      summary: Greet a user
      operationId: hello
      x-google-backend:
        address: -&amp;gt; cloud function address!
      security:
      - keycloak: []
      responses:
        '200':
          description: A successful response
          schema:
            type: string
securityDefinitions:
  # keycloak auth
  keycloak:
    type: oauth2
    flow: implicit
    authorizationUrl: https://KEYCLOA_INSTANCE/auth/realms/test/protocol/openid-connect/auth
    x-google-issuer: https://KEYCLOA_INSTANCE/auth/realms/test
    x-google-jwks_uri: https://KEYCLOA_INSTANCE/auth/realms/test/protocol/openid-connect/certs
    x-google-audiences: test-auth-function-gcp


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

&lt;/div&gt;
&lt;h3&gt;
  
  
  Create your Gateway
&lt;/h3&gt;

&lt;p&gt;Now we can create our API and Gateway.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

# CREATE API
gcloud api-gateway apis create my-api --project=my-project
# CREATE CONFIG
gcloud api-gateway api-configs create my-config \
  --api=my-api --openapi-spec=openapi2-functions.yaml \
  --project=my-project --backend-auth-service-account=0000000000000-compute@developer.gserviceaccount.com
# CREATE GW
gcloud api-gateway gateways create my-gateway \
  --api=my-api --api-config=my-config \
  --location=us-central1 --project=my-project


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

&lt;/div&gt;
&lt;h3&gt;
  
  
  Test!
&lt;/h3&gt;
&lt;h4&gt;
  
  
  Retrieve the gateway address
&lt;/h4&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

gcloud api-gateway gateways describe my-gateway \
  --location=us-central1 --project=my-project


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

&lt;/div&gt;

&lt;p&gt;We get the address from the response of the above command. Check for the &lt;code&gt;defaultHostname&lt;/code&gt; field.&lt;/p&gt;

&lt;h4&gt;
  
  
  Get the JWT Token
&lt;/h4&gt;

&lt;p&gt;I used Keycloak for this demo, so we need to insert our token url and a valid client and user credentials.&lt;/p&gt;

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

curl --request POST \
  --url https://KEYCLOAK/auth/realms/test/protocol/openid-connect/token \
  --header 'Content-Type: application/x-www-form-urlencoded' \
  --data client_id=myclient \
  --data username=myuser \
  --data password=mypassword \
  --data grant_type=password \


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

&lt;/div&gt;

&lt;p&gt;You will get a response like this:&lt;/p&gt;

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

{
    "access_token": "XXXXXX",
    "expires_in": 36000,
    "refresh_expires_in": 1800,
    "refresh_token": "XXXXXX",
    "token_type": "Bearer",
    "not-before-policy": 0,
    "scope": "email profile"
}


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

&lt;/div&gt;

&lt;p&gt;We save the access token, it is needed for the next call.&lt;/p&gt;

&lt;h4&gt;
  
  
  Call the API
&lt;/h4&gt;

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

curl --request GET \
  --url https://hello-gw-xxxxxxx.gateway.dev/hello \
  --header 'Authorization: Bearer XXXXXX'


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

&lt;/div&gt;

&lt;p&gt;We get the "Hello World!" response :)&lt;br&gt;&lt;br&gt;
If we try to make the same call without the authentication bearer token we receive this message:  &lt;/p&gt;


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

&lt;p&gt;{&lt;br&gt;
    "message": "Jwt is missing",&lt;br&gt;
    "code": 401&lt;br&gt;
}&lt;/p&gt;

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

&lt;/div&gt;
&lt;h3&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Deep Dive&lt;br&gt;
&lt;/h3&gt;

&lt;p&gt;If you want to learn more check out these links:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://cloud.google.com/api-gateway/docs/secure-traffic-gcloud" rel="noopener noreferrer"&gt;Secure traffic to a service with the gcloud CLI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cloud.google.com/endpoints/docs/openapi/authenticating-users-custom" rel="noopener noreferrer"&gt;Using a custom method to authenticate users&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cloud.google.com/endpoints/docs/openapi/openapi-extensions" rel="noopener noreferrer"&gt;OpenAPI extensions &lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://datatracker.ietf.org/doc/html/rfc7519" rel="noopener noreferrer"&gt;JSON Web Token (JWT)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://datatracker.ietf.org/doc/html/rfc6749" rel="noopener noreferrer"&gt;OAuth 2.0&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>gcp</category>
      <category>googlecloud</category>
      <category>serverless</category>
      <category>auth</category>
    </item>
  </channel>
</rss>
