import InlineNotification from '@/ds-components/InlineNotification';
import Steps from '@/mdx-components/Steps';
import Step from '@/mdx-components/Step';
import ApplicationCredentials from '@/mdx-components/ApplicationCredentials';
import EnableAdminAccess from './components/EnableAdminAccess';
import EnableAdminAccessSrc from './assets/enable-admin-access.png';
import AppIdentifierSrc from './assets/api-identifier.png';
import { appendPath } from '@silverhand/essentials';
import { isDevFeaturesEnabled } from '@/consts/env';
import AssignManagementApiRole from './assets/assign-mgmt-api-role.webp';
import CreateM2mManagementApiRole from './assets/create-m2m-mgmt-api-role.webp';

<Steps>
<Step title="Intro">

Machine-to-machine (M2M) is a common practice to authenticate if you have an app that needs to directly talk to resources. E.g., an API service that updates users' custom data in Logto, a statistic service that pulls daily orders, etc.

Usually, an M2M app doesn't need user interface.

</Step>
<Step title="Locate the app ID and app secret">

Get your app ID and app secret.

<ApplicationCredentials />

</Step>
<Step title="Locate the API resource">

### Find the API identifier

In the "API resources" page, find the API identifier that the app needs to access. If you haven't added an API resource in Logto or don't know what API resource is, see [API resource](https://docs.logto.io/docs/references/resources).

<img alt="API identifier" src={AppIdentifierSrc} width="600px" style={{ borderRadius: '6px' }} />

</Step>
<Step title="Compose and send request">

### Compose them into a request (all mandatory):

<ul>
  <li>
    Use Token Endpoint <code>{`${appendPath(props.endpoint, '/oidc/token')}`}</code> as the request
    endpoint, and use POST as the method.
  </li>
  <li>
    Set header <code>Content-Type: application/x-www-form-urlencoded</code>
  </li>
  <li>
    Use{' '}
    <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Authorization#basic_authentication">
      Basic authentication
    </a>
    , where username is the app ID, and password is the app secret.
  </li>
  <li>Carry the body data</li>
</ul>

```json
{
  "grant_type": "client_credentials",
  "resource": "https://shopping.api", // Replace with your API identifier
  "scope": "scope_1 scope_2" // Replace with your desired scope(s) if you're using RBAC
}
```

If you are using cURL:

<pre>
  <code className="language-bash">
    {`curl --location
  --request POST '${appendPath(props.endpoint, '/oidc/token')}'
  # Credentials are constructed by "<app-id>:<app-secret>" and encoded in base64
  --header 'Authorization: Basic ${Buffer.from(`${props.app.id}:${props.app.secret}`).toString(
    'base64'
  )}'
  --header 'Content-Type: application/x-www-form-urlencoded'
  --data-urlencode 'grant_type=client_credentials'
  --data-urlencode 'resource=https://shopping.api'
  --data-urlencode 'scope=scope_1 scope_2'
`}
  </code>
</pre>

### Token response

A successful response body would be like:

```json
{
  "access_token": "<granted-access-token>", // Use this token to access the API resource
  "expires_in": 3600, // Token expiration in seconds
  "token_type": "Bearer" // Auth type for your request when using the access token
}
```

</Step>
<Step title="Access API resource using access token">

You may notice the token response has a `token_type` field, which it's fixed to `Bearer`. Thus you should put the access token in the `Authorization` field of HTTP headers with the Bearer format (`Bearer <your-access-token>`).

For example, if you have acquired an access token with your "Online Shopping" API resource `https://shopping.api`, then you can send requests to the API resource to achieve some your business logic.

Here is an example of using cURL to send a GET request to get items in your shopping cart:

<pre>
  <code className="language-bash">
    {`curl --location
  --request GET 'https://shopping.api/my/cart/items'
  --header 'Authorization: Bearer <granted-access-token>'
`}
  </code>
</pre>

</Step>
<Step title="Enable admin access" subtitle="(optional)">

  ### Accessing Logto Management API

  If you want to use this m2m app to access Logto [Management API](https://docs.logto.io/docs/references/core/#management-api).

  You should go to "Roles" tab and create a new machine-to-machine role with the permission of management API.

  <img
    alt="Create m2m management API role"
    src={CreateM2mManagementApiRole}
    width="600px"
    style={{ borderRadius: '6px' }}
  />

  And then go to the "Roles" tab under machine to machine app detail page, and assign the role you just created to the app.

  <img
    alt="Assign m2m management API role to app"
    src={AssignManagementApiRole}
    width="600px"
    style={{ borderRadius: '6px' }}
  />

</Step>
</Steps>
