Integrate OAuth to Go service without pain
with the help of Mify cli
What is OAuth?
Originally, OAuth was designed to give a way to access user data by third-party applications without user password sharing. It makes a lot of sense for big companies such as Google, Microsoft, etc. which have millions of internal services and even more integrations with external services. This allows site owners to implement this convenient button "sign up with Google". You, as a user just being redirected to the Google authorization page where you agree to share with an external site a bit of data stored in your Google account.
Do you need OAuth for your service?
At this point you can have a valid question: Do I need such complexity for my small Go service, I'm not going to share any data with third-party applications or websites.
I will give you at least 3 reasons why OAuth can simplify your life:
OAuth protocol is not only about data sharing. It is also an authorization (and with some extension authentification) protocol. It means you can use it to secure access to your service API.
OAuth allows us to move out most of the authentication/authorization complexity to external providers, such as https://auth0.com/ (this link is given only as an example, there are many OAuth providers, and the steps described in this article should work with any of them).
There are a lot of ready solutions that you can reuse in your service.
Prerequisites
In this article, I will use the open-source tool, called Mify. This tool is supposed to help software developers avoid writing the same repetitive infrastructure code from service to service, such as metrics/logs sending and collecting, open API generator, dynamic configs readers, etc. And one of the supported features is OAuth integration, which is very useful for our case.
Get Mify from our GitHub: https://github.com/mify-io/mify
Install Postman or Curl to test endpoints
Register a new account in Auth0. You can use any OAuth provider, but in this article, all examples will be given for Auth0.
Creating new service
If you have already created a service with Mify cli before, you can skip this paragraph. Otherwise, you can clone the ready service from https://github.com/mify-io/examples/tree/main/oauth-example. It is a very simple service generated with Mify cli, which has 3 APIs: create a new book, return the book by ID, and return all stored books.
Configuring Auth0
Before we can start implementing authorization in our service, we need to apply some configuration in Auth0. To do so, please follow the manual for registering a new API inside Auth0.
For now, we've created an Auth0 API, which represents our go service. But we also need to create an Auth0 application. The application represents some type of app that can access API. For example, it could be your frontend SPA, some other external service, etc. Each type of application can have different ways of obtaining auth tokens, we will not focus on that in this article. To create an Application, you should go to the applications tab and press "Create application":

And chose "Machine to Machine Applications" template:

After that, we need to allow this application to access API created before. For that, return to API settings page and authorize your application on "Machine to Machine Applications" tab:

Adding OAuth to the service
Now we are ready to add authorization to our service. To do that, first, you need to find out your API identifier. You can find it inside Auth0:

Then you need to go schemas/<your_service_name>/api/api.yaml inside your Mify workspace. In this file, you will need to add 2 new items. One inside components section and one before paths section (on the same level):
openapi: "3.0.0"
info: ...
servers: ...
security: # This is first added section
- auth0: []
paths: ...
components:
...
securitySchemes: # This is second added section
openIdSample:
type: openIdConnect
openIdConnectUrl: https://mifyio.us.auth0.com/.well-known/openid-configuration
x-mify-audience: https://auth-example.mify.io
Note: You should replace openIdConnectUrl and x-mify-audience values with your own values, which can be found on the test tab of your application:

In this example, we are using OpenAPI schema. According to this schema, all possible security schemas should be described inside components.securitySchemes.
Then we can use a defined security schema for protecting our API. In the example before, we added it inside security the section. When we add this section to the top level of API schema, this security schema will be applied to all APIs in our service. We don't require any special permission yet, the only thing that will be validated at this point is that API client sent a valid Bearer token, with the right audience.
Testing
Now we can check if it works as we are expecting. To do so, we need to generate code for our new API description. Go to Mify workspace and call:
$ mify generate
Now our service is ready for running:
$ cd go-services
$ go run ./cmd/books-service-origin # Note: replace books-service-origin with your service name
{"level":"info","@timestamp":"2023-08-09T21:16:43.892489615+01:00","caller":"app/mify_app.go:91","msg":"Starting...","service_name":"books-service-origin","hostname":"DESKTOP-M0007IE"}
{"level":"info","@timestamp":"2023-08-09T21:16:43.892542463+01:00","caller":"app/server.go:38","msg":"starting api server","service_name":"books-service-origin","hostname":"DESKTOP-M0007IE","endpoint":":38259"}
{"level":"info","@timestamp":"2023-08-09T21:16:43.892565087+01:00","caller":"app/server.go:38","msg":"starting maintenance server","service_name":"books-service-origin","hostname":"DESKTOP-M0007IE","endpoint":":33897"}
This command will start your service and during that, it will write some logs to your screen. You need to find starting api server one. In this log, inside endpoint field, you will find a port that you can use to access your service on localhost. Then you can access your service API on localhost:<endpoint>. In this article, I will use Postman for sending HTTP requests to my service, but you also can use curl or any other tool.
Let's try to execute PUT localhost:<endpoint>/books: with body {"name": "test name}

You will get 401 Unauthorized with {"message": "Authorization header missing"} now. That's because we didn't include any authorization header in our request. Let's fix that. To obtain a token, you can go back to your API page (inside Auth0) and then switch to the Test tab:

Then just choose your application, and copy the generated curl request. You can execute this curl in your terminal, or import it to Postman. Then you will receive access_token in response.

Now we can include this token in our request for service. To do that, add a new Header with Key="Authorization" and Value="Bearer <your_token>" and send the request to the server:

As you can see, now we get response 200 OK. Now we can execute GET localhost:<endpoint>/books to view a list of all books

Implementing authorization
At this point, our service requires a client to include a valid Authorization token, generated by Auth0. Our service validates that this token is issued by a trusted provider (in our case it was Auth0). This part is usually called authentication - the service can find out who is this user calling it (there is some info about it in the token).
But in real applications, we need some way to limit access to different APIs for different users. There should be users who can create and read books. And there should be users who can only read books. This part is called authorization and Mify can help with this too, but it will be covered in the next articles.
Summary
In most cases, implementing authentification and authorization for your service is a very complicated task. There are a lot of things developers need to know and keep in mind to avoid mistakes, which could cause critical security vulnerabilities. But all this work can be automated, and one of the ways to automate that is to use Mify. With it, you will need to add a couple of lines to your API configuration, which will specify what exactly you need and all code will be generated for you.