Getting Started

In this journey we log-in as a user, administrator creates a new service for us and makes us as the owner of the service. After that we create a policy to allow the project owners (assume project is a resource in your service) to have write permission on their projects. After evaluating the owner permissions, we create a reporter role, use the role in our policies to allow reporters read all projects. Then authorize our users to check if they have permission to read all projects when they send a request to our service to read all projects. Finally, we get the client_secret to run OAuth2 flows later.

Part one: Authorize using policies

  • Login and get a user token. Let's say the token is user_token_abc.

  • Get your user id

curl --location --request GET 'localhost:4000/api/v1/user' \
--header 'Authorization: Bearer user_token_abc'

It will gives you a response like this:

{
    "code": "shield.user.success_get_user",
    "data": {
        "city_code": null,
        "enabled": true,
        "first_name": null,
        "id": "user_id_abc",
        "is_service": false,
        "last_name": null,
        "phone": "+989366570909",
        "roles": [],
        "state_code": null
    }
}

Extract your user id from the response. In this case its user_id_abc.

  • Just administrator can create a new service for you. ask them to create a new service and make you as the service's owner. They should give you a service_id too. From now on we assume our service's id is service_id_abc.

  • Create a client scope in your service:

curl -X POST --location "localhost:4000/api/v1/client-scopes" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -H "Authorization: Bearer user_token_abc" \
    -d '{
        "service_id":"service_id_abc",
        "code":"all",
        "label": "access to everything"
        }'
  • Create a client in your service. You cal also ask the administrator to do it for you, if you don't know what is the best value for some params in the request
curl --location --request POST 'localhost:4000/api/v1/clients' \
--header 'Authorization: Bearer user_token_abc' \
--header 'Content-Type: application/json' \
--data-raw '{
    "name": "gateway",
    "owner_id": "user_id_abc",
    "service_id":"service_id_abc",
    "redirect_uris": [
        "http://gateway.local:3000/oauth2/redirect"
    ],
    "allowed_grants": [
        "authorization_code",
        "password",
        "client_credentials",
        "refresh_token",
        "_implicit"
    ],
    "allowed_scopes": ["all"],
    "grants_config": {
        "authorization_code": {
            "code_expires_in": 3600000000000,
            "generate_refresh_token": true,
            "access_token_expires_in": 259200000000000,
            "refresh_token_expires_in": 1036800000000000,
            "force_pkce": false,
            "allowed_code_challenge_methods": null
        },
        "implicit": {
            "access_token_expires_in": 0
        },
        "password_credentials": {
            "generate_refresh_token": true,
            "access_token_expires_in": 259200000000000,
            "refresh_token_expires_in": 1036800000000000
        },
        "client_credentials": {
            "access_token_expires_in": 2592000000000000
        },
        "refresh_token": {
            "remove_old_access_and_refresh_tokens": true,
            "generate_new_refresh_token": true,
            "reset_refresh_token_expiry": true
        }
    }
}'

It will give you a response like this:

{
  "code": "shield.client.created",
  "data": {
    "client_id": "2022123141810.w5evivuykgxkxyu",
    "id": "61ed326afac39b3bcd69750b",
    "name": "gateway",
    "owner_id": "61dd6fa13418a4f5969ddd38",
    "service_account_id": "",
    "service_id": "service_id_abc"
  }
}

Now we have a new client with client ID 2022123141810.w5evivuykgxkxyu.

  • To send requests for role creation and ... we need to a token, but not our own personal token. we do use it, but it just for personal usage, not service-service calls. For service-service calls it is better to get a client token:
curl --location --request POST 'localhost:4000/api/v1/clients/2022123141810.w5evivuykgxkxyu/token' \
--header 'Authorization: Bearer user_token_abc'
--data-raw ''

It will gives us the token:

{
  "code": "shield.client.success_generate_token",
  "data": {
    "access_token": "yzughv4s1c29l6ige4xt2quuiil4k7",
    "expires_in": 2592000,
    "scope": "all",
    "token_type": "Bearer"
  }
}

The token is yzughv4s1c29l6ige4xt2quuiil4k7. From now on we use this token in our next requests to the shield server.

  • Create a policy in your service. allow users who are owner of the project to allow writing on the project.
curl --location --request POST 'localhost:4000/api/v1/policies' \
--header 'Authorization: Bearer yzughv4s1c29l6ige4xt2quuiil4k7' \
--header 'Content-Type: application/json' \
--data-raw '{
    "service_id": "service_id_abc",
    "res_type": "project",
    "condition": {
        "operator": "eq",
        "operands": [
            {
                "value": "{res.owner_id}"
            },
            {
                "value": "{user.id}"
            }
        ]
    },
    "decision": 1
}'

Notes:
The decision with value 1 meaning give permission to the user if policy is match. You will read more about it in the policies section.

The condition checks if user is owner of the resource. so in our authorization request we should send the resource's owner_id too.

  • Authorize the user:
    Assume someone sends a request to update the project in your service. You need to check if the user has permission to the project in write scope. So send a request like the following from your service:

Assume id of the user who is sending the request to your server is user_id_123.
You should get the owner_id prop's value for project with id 4 from your service's database.

curl --location --request POST 'localhost:4000/api/v1/gate/authorize' \
--header 'Authorization: Bearer yzughv4s1c29l6ige4xt2quuiil4k7' \
--header 'Content-Type: application/json' \
--data-raw '{
    "service_id":"service_id_abc",
    "user_id":"user_id_123",
    "permissions":[
        {
            "resource_attributes":[{"key":"owner_id","value":"user_id_123"}],
            "permission":"project:4",
            "scope":"write"
        }
    ]
}'

The response will be like this:

  {
  "code": "shield.gate.success_evaluation",
  "data": {
    "permissions": [
      "project:4"
    ]
  }
}

which shows that user has permission to the project.

If we send a request like this:

curl --location --request POST 'localhost:4000/api/v1/gate/authorize' \
--header 'Authorization: Bearer yzughv4s1c29l6ige4xt2quuiil4k7' \
--header 'Content-Type: application/json' \
--data-raw '{
    "service_id":"service_id_abc",
    "user_id":"user_id_123",
    "permissions":[
        {
            "resource_attributes":[{"key":"owner_id","value":"user_another_id_987"}],
            "permission":"project:4",
            "scope":"write"
        }
    ]
}'

The response will be an empty array for permissions:

{
  "code": "shield.gate.success_evaluation",
  "data": {
    "permissions": []
  }
}

Part two: Use roles

  • Create a reporter role.
curl --location --request POST 'localhost:4000/api/v1/roles' \
--header 'Authorization: Bearer yzughv4s1c29l6ige4xt2quuiil4k7' \
--header 'Content-Type: application/json' \
--data-raw '{
    "service_id":"service_id_abc",
    "name":"reporter",
    "code":"reporter"
}'

Response should be something like this:

{
  "code": "shield.role.created",
  "data": {
    "code": "reporter",
    "id": "61ed4c44d7004f94898abd42",
    "name": "reporter",
    "service_id": "service_id_abc"
  }
}
  • Create a policy to allow reporters to read all projects.
curl --location --request POST 'localhost:4000/api/v1/policies' \
--header 'Authorization: Bearer yzughv4s1c29l6ige4xt2quuiil4k7' \
--header 'Content-Type: application/json' \
--data-raw '{
    "service_id": "service_id_abc",
    "role_code":"reporter",
    "res_type": "project",
    "scopes": ["read"],
    "decision": 1
}'
  • Assign reporter role to a user.
curl --location --request POST 'localhost:4000/api/v1/user/user_id_123/roles/reporter' \
--header 'Authorization: Bearer yzughv4s1c29l6ige4xt2quuiil4k7' 

The Response will be something like this:

{
  "code": "shield.user.role.success_add",
  "data": {}
}

It shows that we have added the role to the user's roles list.

  • Send authorization request to read all projects by a reporter: We know that user with id user_id_123 is a reporter. so now we can check when a user wants to read all projects:
curl --location --request POST 'localhost:4000/api/v1/gate/authorize' \
--header 'Authorization: Bearer yzughv4s1c29l6ige4xt2quuiil4k7' \
--header 'Content-Type: application/json' \
--data-raw '{
    "service_id":"service_id_abc",
    "user_id":"user_id_123",
    "permissions":[
        {
            "permission":"project",
            "scope":"read"
        }
    ]
}'

You will get a resonse like this:

{
  "code": "shield.gate.success_evaluation",
  "data": {
    "permissions": [
      "project"
    ]
  }
}

It shows that user has permission to all projects.

Part three: OAuth2 flows

  • Next step is getting the client's secret. Get and keep it in a safe place (and use it in your service to start oauth2 flows later)
curl --location --request POST 'localhost:4000/api/v1/clients/2022123141810.w5evivuykgxkxyu/secret' \
--header 'Authorization: Bearer user_token_abc' 

It will give youn a response which contains the client's secret:

{
  "code": "shield.client.success_get_secret",
  "data": {
    "secret": "m0tsoxw0zikfxf2nd08kc7n3tudt9p"
  }
}

Now we have a client_id and a client_secret to run our OAuth2 and OIDC flows.

Last Updated: