Introduce STS client grants API and OPA policy integration (#6168)

This PR introduces two new features

- AWS STS compatible STS API named AssumeRoleWithClientGrants

```
POST /?Action=AssumeRoleWithClientGrants&Token=<jwt>
```

This API endpoint returns temporary access credentials, access
tokens signature types supported by this API

  - RSA keys
  - ECDSA keys

Fetches the required public key from the JWKS endpoints, provides
them as rsa or ecdsa public keys.

- External policy engine support, in this case OPA policy engine

- Credentials are stored on disks
This commit is contained in:
Harshavardhana
2018-10-09 14:00:01 -07:00
committed by kannappanr
parent 16a100b597
commit 54ae364def
76 changed files with 7249 additions and 713 deletions

51
docs/sts/README.md Normal file
View File

@@ -0,0 +1,51 @@
# Minio STS Quickstart Guide [![Slack](https://slack.minio.io/slack?type=svg)](https://slack.minio.io)
The Minio Security Token Service (STS) is an endpoint service that enables clients to request temporary credentials for Minio resources. Temporary credentials work almost identically to default admin credentials, with some differences:
- Temporary credentials are short-term, as the name implies. They can be configured to last for anywhere from a few minutes to several hours. After the credentials expire, Minio no longer recognizes them or allows any kind of access from API requests made with them.
- Temporary credentials do not need to be stored with the application but are generated dynamically and provided to the application when requested. When (or even before) the temporary credentials expire, the application can request new credentials.
Following are advantages for using temporary credentials:
- No need embed long-term credentials with an application.
- No need to provide access to buckets and objects without having to define static credentials.
- Temporary credentials have a limited lifetime, no need to rotate them or explicitly revoke them when they're no longer needed. After temporary credentials expire, they cannot be reused.
## Identity Federation
[**Client grants**](./client-grants.md) - Let applications request `client_grants` using any well-known third party identity provider such as KeyCloak, WSO2. This is known as the client grants approach to temporary access. Using this approach helps clients keep Minio credentials to be secured. Minio STS client grants supports WSO2, Keycloak.
## Get started
In this document we will explain in detail on how to configure all the prerequisites, primarily WSO2, OPA (open policy agent).
### 1. Prerequisites
- [Configuring wso2](./wso2.md)
- [Configuring opa](./opa.md)
### 2. Setup Minio with WSO2, OPA
Make sure we have followed the previous step and configured each software independently, once done we can now proceed to use Minio STS API and Minio server to use these credentials to perform object API operations.
```
export MINIO_ACCESS_KEY=minio
export MINIO_SECRET_KEY=minio123
export MINIO_IAM_JWKS_URL=https://localhost:9443/oauth2/jwks
export MINIO_IAM_OPA_URL=http://localhost:8181/v1/data/httpapi/authz
minio server /mnt/data
```
### 3. Test using full-example.go
On another terminal run `full-example.go` a sample client application which obtains JWT access tokens from an identity provider, in our case its WSO2. Uses the returned access token response to get new temporary credentials from the Minio server using the STS API call `AssumeRoleWithClientGrants`.
```
go run full-example.go -cid PoEgXP6uVO45IsENRngDXj5Au5Ya -csec eKsw6z8CtOJVBtrOWvhRWL4TUCga
##### Credentials
{
"accessKey": "NUIBORZYTV2HG2BMRSXR",
"secretKey": "qQlP5O7CFPc5m5IXf1vYhuVTFj7BRVJqh0FqZ86S",
"expiration": "2018-08-21T17:10:29-07:00",
"sessionToken": "eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJhY2Nlc3NLZXkiOiJOVUlCT1JaWVRWMkhHMkJNUlNYUiIsImF1ZCI6IlBvRWdYUDZ1Vk80NUlzRU5SbmdEWGo1QXU1WWEiLCJhenAiOiJQb0VnWFA2dVZPNDVJc0VOUm5nRFhqNUF1NVlhIiwiZXhwIjoxNTM0ODk2NjI5LCJpYXQiOjE1MzQ4OTMwMjksImlzcyI6Imh0dHBzOi8vbG9jYWxob3N0Ojk0NDMvb2F1dGgyL3Rva2VuIiwianRpIjoiNjY2OTZjZTctN2U1Ny00ZjU5LWI0MWQtM2E1YTMzZGZiNjA4In0.eJONnVaSVHypiXKEARSMnSKgr-2mlC2Sr4fEGJitLcJF_at3LeNdTHv0_oHsv6ZZA3zueVGgFlVXMlREgr9LXA"
}
```
## Explore Further
- [Minio STS Quickstart Guide](https://docs.minio.io/docs/minio-sts-quickstart-guide)
- [The Minio documentation website](https://docs.minio.io)

71
docs/sts/client-grants.md Normal file
View File

@@ -0,0 +1,71 @@
## AssumeRoleWithClientGrants [![Slack](https://slack.minio.io/slack?type=svg)](https://slack.minio.io)
Returns a set of temporary security credentials for applications/clients who have been authenticated through client grants provided by identity provider. Example providers include WSO2, KeyCloak etc.
Calling AssumeRoleWithClientGrants does not require the use of Minio default credentials. Therefore, client application can be distributed that requests temporary security credentials without including Minio default credentials. Instead, the identity of the caller is validated by using a JWT access token from the identity provider. The temporary security credentials returned by this API consist of an access key, a secret key, and a security token. Applications can use these temporary security credentials to sign calls to Minio API operations.
By default, the temporary security credentials created by AssumeRoleWithClientGrants last for one hour. However, use the optional DurationSeconds parameter to specify the duration of the credentials. This value varies from 900 seconds (15 minutes) up to the maximum session duration to 12 hours.
### Request Parameters
#### DurationSeconds
The duration, in seconds. The value can range from 900 seconds (15 minutes) up to the 12 hours. If value is higher than this setting, then operation fails. By default, the value is set to 3600 seconds.
| Params | Value |
| :-- | :-- |
| *Type* | *Integer* |
| *Valid Range* | *Minimum value of 900. Maximum value of 43200.* |
| *Required* | *No* |
#### Token
The OAuth 2.0 access token that is provided by the identity provider. Application must get this token by authenticating the application using client grants before the application makes an AssumeRoleWithClientGrants call.
| Params | Value |
| :-- | :-- |
| *Type* | *String* |
| *Length Constraints* | *Minimum length of 4. Maximum length of 2048.* |
| *Required* | *Yes* |
#### Response Elements
XML response for this API is similar to [AWS STS AssumeRoleWithWebIdentity](https://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRoleWithWebIdentity.html#API_AssumeRoleWithWebIdentity_ResponseElements)
#### Errors
XML error response for this API is similar to [AWS STS AssumeRoleWithWebIdentity](https://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRoleWithWebIdentity.html#API_AssumeRoleWithWebIdentity_Errors)
#### Testing
```
$ export MINIO_ACCESS_KEY=minio
$ export MINIO_SECRET_KEY=minio123
$ export MINIO_IAM_JWKS_URL=https://localhost:9443/oauth2/jwks
$ export MINIO_IAM_OPA_URL=http://localhost:8181/v1/data/httpapi/authz
$ minio server /mnt/export
$ mc admin config get myminio
...
{
"openid": {
"jwks": {
"url": "https://localhost:9443/oauth2/jwks"
}
}
"policy": {
"opa": {
"url": "http://localhost:8181/v1/data/httpapi/authz",
"authToken": ""
}
}
}
```
Testing with an example
> Obtaining client ID and secrets follow [WSO2 configuring documentation](./wso2.md)
```
go run full-example.go -cid PoEgXP6uVO45IsENRngDXj5Au5Ya -csec eKsw6z8CtOJVBtrOWvhRWL4TUCga
##### Credentials
{
"accessKey": "NUIBORZYTV2HG2BMRSXR",
"secretKey": "qQlP5O7CFPc5m5IXf1vYhuVTFj7BRVJqh0FqZ86S",
"expiration": "2018-08-21T17:10:29-07:00",
"sessionToken": "eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJhY2Nlc3NLZXkiOiJOVUlCT1JaWVRWMkhHMkJNUlNYUiIsImF1ZCI6IlBvRWdYUDZ1Vk80NUlzRU5SbmdEWGo1QXU1WWEiLCJhenAiOiJQb0VnWFA2dVZPNDVJc0VOUm5nRFhqNUF1NVlhIiwiZXhwIjoxNTM0ODk2NjI5LCJpYXQiOjE1MzQ4OTMwMjksImlzcyI6Imh0dHBzOi8vbG9jYWxob3N0Ojk0NDMvb2F1dGgyL3Rva2VuIiwianRpIjoiNjY2OTZjZTctN2U1Ny00ZjU5LWI0MWQtM2E1YTMzZGZiNjA4In0.eJONnVaSVHypiXKEARSMnSKgr-2mlC2Sr4fEGJitLcJF_at3LeNdTHv0_oHsv6ZZA3zueVGgFlVXMlREgr9LXA"
}
```

View File

@@ -0,0 +1,17 @@
version: '2'
services:
opa:
image: openpolicyagent/opa:0.9.1
ports:
- 8181:8181
command:
- "run"
- "--server"
- "--log-level=debug"
api_server:
image: openpolicyagent/demo-restful-api:0.2
ports:
- 5000:5000
environment:
- OPA_ADDR=http://opa:8181
- POLICY_PATH=/v1/data/httpapi/authz

180
docs/sts/full-example.go Normal file
View File

@@ -0,0 +1,180 @@
/*
* Minio Cloud Storage, (C) 2018 Minio, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package main
import (
"bytes"
"crypto/tls"
"encoding/json"
"encoding/xml"
"flag"
"fmt"
"log"
"net/http"
"net/url"
"strings"
minio "github.com/minio/minio-go"
"github.com/minio/minio-go/pkg/credentials"
"github.com/minio/minio/pkg/auth"
)
// AssumedRoleUser - The identifiers for the temporary security credentials that
// the operation returns. Please also see https://docs.aws.amazon.com/goto/WebAPI/sts-2011-06-15/AssumedRoleUser
type AssumedRoleUser struct {
Arn string
AssumedRoleID string `xml:"AssumeRoleId"`
// contains filtered or unexported fields
}
// AssumeRoleWithClientGrantsResponse contains the result of successful AssumeRoleWithClientGrants request.
type AssumeRoleWithClientGrantsResponse struct {
XMLName xml.Name `xml:"https://sts.amazonaws.com/doc/2011-06-15/ AssumeRoleWithClientGrantsResponse" json:"-"`
Result ClientGrantsResult `xml:"AssumeRoleWithClientGrantsResult"`
ResponseMetadata struct {
RequestID string `xml:"RequestId,omitempty"`
} `xml:"ResponseMetadata,omitempty"`
}
// ClientGrantsResult - Contains the response to a successful AssumeRoleWithClientGrants
// request, including temporary credentials that can be used to make Minio API requests.
type ClientGrantsResult struct {
AssumedRoleUser AssumedRoleUser `xml:",omitempty"`
Audience string `xml:",omitempty"`
Credentials auth.Credentials `xml:",omitempty"`
PackedPolicySize int `xml:",omitempty"`
Provider string `xml:",omitempty"`
SubjectFromClientGrantsToken string `xml:",omitempty"`
}
// JWTToken - parses the output from IDP access token.
type JWTToken struct {
AccessToken string `json:"access_token"`
Expiry int `json:"expires_in"`
}
var (
stsEndpoint string
idpEndpoint string
clientID string
clientSecret string
)
func init() {
flag.StringVar(&stsEndpoint, "sts-ep", "http://localhost:9000", "STS endpoint")
flag.StringVar(&idpEndpoint, "idp-ep", "https://localhost:9443/oauth2/token", "IDP endpoint")
flag.StringVar(&clientID, "cid", "", "Client ID")
flag.StringVar(&clientSecret, "csec", "", "Client secret")
}
func main() {
flag.Parse()
if clientID == "" || clientSecret == "" {
flag.PrintDefaults()
return
}
data := url.Values{}
data.Set("grant_type", "client_credentials")
req, err := http.NewRequest(http.MethodPost, idpEndpoint, strings.NewReader(data.Encode()))
if err != nil {
log.Fatal(err)
}
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
req.SetBasicAuth(clientID, clientSecret)
t := &http.Transport{
TLSClientConfig: &tls.Config{
InsecureSkipVerify: true,
},
}
hclient := http.Client{
Transport: t,
}
resp, err := hclient.Do(req)
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
log.Fatal(resp.Status)
}
var idpToken JWTToken
if err = json.NewDecoder(resp.Body).Decode(&idpToken); err != nil {
log.Fatal(err)
}
v := url.Values{}
v.Set("Action", "AssumeRoleWithClientGrants")
v.Set("Token", idpToken.AccessToken)
v.Set("DurationSeconds", fmt.Sprintf("%d", idpToken.Expiry))
u, err := url.Parse(stsEndpoint)
if err != nil {
log.Fatal(err)
}
u.RawQuery = v.Encode()
req, err = http.NewRequest("POST", u.String(), nil)
if err != nil {
log.Fatal(err)
}
resp, err = http.DefaultClient.Do(req)
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
log.Fatal(resp.Status)
}
a := AssumeRoleWithClientGrantsResponse{}
if err = xml.NewDecoder(resp.Body).Decode(&a); err != nil {
log.Fatal(err)
}
fmt.Println("##### Credentials")
c, err := json.MarshalIndent(a.Result.Credentials, "", "\t")
if err != nil {
log.Fatal(err)
}
fmt.Println(string(c))
// Uncommend this to use Minio API operations by initializin minio
// client with obtained credentials.
opts := &minio.Options{
Creds: credentials.NewStaticV4(a.Result.Credentials.AccessKey,
a.Result.Credentials.SecretKey,
a.Result.Credentials.SessionToken,
),
BucketLookup: minio.BucketLookupAuto,
}
clnt, err := minio.NewWithOptions(u.Host, opts)
if err != nil {
log.Fatal(err)
}
d := bytes.NewReader([]byte("Hello, World"))
n, err := clnt.PutObject("my-bucketname", "my-objectname", d, d.Size(), minio.PutObjectOptions{})
if err != nil {
log.Fatalln(err)
}
log.Println("Uploaded", "my-objectname", " of size: ", n, "Successfully.")
}

85
docs/sts/opa.md Normal file
View File

@@ -0,0 +1,85 @@
# OPA Quickstart Guide [![Slack](https://slack.minio.io/slack?type=svg)](https://slack.minio.io)
OPA is a lightweight general-purpose policy engine that can be co-located with Minio server, in this document we talk about how to use OPA HTTP API to authorize Minio STS credentials.
## Get started
### 1. Prerequisites
- Docker 18.03 or above, refer here for [installation](https://docs.docker.com/install/).
- Docker compose 1.20 or above, refere here for [installation](https://docs.docker.com/compose/install/#prerequisites).
### 2. Start OPA
First, create a `docker-compose.yml` file that runs OPA and the demo web server.
```
cat >docker-compose.yml <<EOF
version: '2'
services:
opa:
image: openpolicyagent/opa:0.9.1
ports:
- 8181:8181
command:
- "run"
- "--server"
- "--log-level=debug"
api_server:
image: openpolicyagent/demo-restful-api:0.2
ports:
- 5000:5000
environment:
- OPA_ADDR=http://opa:8181
- POLICY_PATH=/v1/data/httpapi/authz
EOF
```
Then run `docker-compose` to pull and run the containers.
```
docker-compose -f docker-compose.yml up
```
### 3. Create new OPA Policy
In another terminal, create a policy that allows users to upload objects
```
cat > putobject.rego <<EOF
package httpapi.authz
import input as http_api
allow {
input.action = "s3:PutObject"
input.owner = false
}
EOF
```
Then load the policy via OPA's REST API.
```
curl -X PUT --data-binary @putobject.rego \
localhost:8181/v1/policies/putobject
```
### 4. Setup Minio with OPA
Minio server expects environment variable for OPA http API url as `MINIO_IAM_OPA_URL`, this environment variable takes a single entry.
```
export MINIO_IAM_OPA_URL=http://localhost:8181/v1/data/httpapi/authz
minio server /mnt/data
```
### 5. Test with Minio STS API
Assuming that Minio server is configured to support STS API by following the doc [Minio STS Quickstart Guide](https://docs.minio.io/docs/minio-sts-quickstart-guide), execute the following command to temporary credentials from Minio server.
```
go run full-example.go -cid PoEgXP6uVO45IsENRngDXj5Au5Ya -csec eKsw6z8CtOJVBtrOWvhRWL4TUCga
##### Credentials
{
"accessKey": "IRBLVDGN5QGMDCMO1X8V",
"secretKey": "KzS3UZKE7xqNdtRbKyfcWgxBS6P1G4kwZn4DXKuY",
"expiration": "2018-08-21T15:49:38-07:00",
"sessionToken": "eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJhY2Nlc3NLZXkiOiJJUkJMVkRHTjVRR01EQ01PMVg4ViIsImF1ZCI6IlBvRWdYUDZ1Vk80NUlzRU5SbmdEWGo1QXU1WWEiLCJhenAiOiJQb0VnWFA2dVZPNDVJc0VOUm5nRFhqNUF1NVlhIiwiZXhwIjoxNTM0ODkxNzc4LCJpYXQiOjE1MzQ4ODgxNzgsImlzcyI6Imh0dHBzOi8vbG9jYWxob3N0Ojk0NDMvb2F1dGgyL3Rva2VuIiwianRpIjoiMTg0NDMyOWMtZDY1YS00OGEzLTgyMjgtOWRmNzNmZTgzZDU2In0.4rKsZ8VkZnIS_ALzfTJ9UbEKPFlQVvIyuHw6AWTJcDFDVgQA2ooQHmH9wUDnhXBi1M7o8yWJ47DXP-TLPhwCgQ"
}
```
These credentials can now be used to perform Minio API operations, these credentials automatically expire in 1hr. To understand more about credential expiry duration and client grants STS API read further [here](https://docs.minio.io/docs/api-assume-role-with-client-grants).
## Explore Further
- [Minio STS Quickstart Guide](https://docs.minio.io/docs/minio-sts-quickstart-guide)
- [The Minio documentation website](https://docs.minio.io)

4
docs/sts/sts.env Normal file
View File

@@ -0,0 +1,4 @@
export MINIO_ACCESS_KEY=minio
export MINIO_SECRET_KEY=minio123
export MINIO_IAM_JWKS_URL=http://localhost:9763/oauth2/jwks
export MINIO_IAM_OPA_URL=http://localhost:8181/v1/data/httpapi/authz

88
docs/sts/wso2.md Normal file
View File

@@ -0,0 +1,88 @@
# WSO2 Quickstart Guide [![Slack](https://slack.minio.io/slack?type=svg)](https://slack.minio.io)
WSO2 is an Identity Server open source and is released under Apache Software License Version 2.0, this document covers configuring WSO2 to be used as an identity provider for Minio server STS API.
## Get started
### 1. Prerequisites
- JAVA 1.8 and above installed already and JAVA_HOME points to JAVA 1.8 installation.
- Download WSO2 follow their [installation guide](https://docs.wso2.com/display/IS540/Installation+Guide).
### 2. Configure WSO2
Once WSO2 is up and running, configure WSO2 to generate Self contained access tokens. In OAuth 2.0 specification there are primarily two ways to provide access tokens
1. The access token is an identifier that is hard to guess. For example, a randomly generated string of sufficient length, that the server handling the protected resource can use to lookup the associated authorization information.
2. The access token self-contains the authorization information in a manner that can be verified. For example, by encoding authorization information along with a signature into the token.
WSO2 generates tokens in first style by default, but if to be used with Minio we should configure WSO2 to provide JWT tokens instead.
### 3. Generate Self-contained Access Tokens
By default, a UUID is issued as an access token in WSO2 Identity Server, which is of the first type above. But, it also can be configured to issue a self-contained access token (JWT), which is of the second type above.
- Open the `<IS_HOME>/repository/conf/identity/identity.xml` file and uncomment the following entry under `<OAuth>` element.
```
<IdentityOAuthTokenGenerator>org.wso2.carbon.identity.oauth2.token.JWTTokenIssuer</IdentityOAuthTokenGenerator>
```
- Restart the server.
- Configure an [OAuth service provider](https://docs.wso2.com/display/IS540/Adding+and+Configuring+a+Service+Provider).
- Initiate an access token request to the WSO2 Identity Server, over a known [grant type](https://docs.wso2.com/display/IS540/OAuth+2.0+Grant+Types). For example, the following cURL command illustrates the syntax of an access token request that can be initiated over the [Client Credentials Grant](https://docs.wso2.com/display/IS540/Client+Credentials+Grant) grant type.
- Navigate to service provider section, expand Inbound Authentication Configurations and expand OAuth/OpenID Connect Configuration.
- Copy the OAuth Client Key as the value for `<CLIENT_ID>`.
- Copy the OAuth Client Secret as the value for `<CLIENT_SECRET>`.
- By default, `<IS_HOST>` is localhost. However, if using a public IP, the respective IP address or domain needs to be specified.
- By default, `<IS_HTTPS_PORT>` has been set to 9443. However, if the port offset has been incremented by n, the default port value needs to be incremented by n.
Request
```
curl -u <CLIENT_ID>:<CLIENT_SECRET> -k -d "grant_type=client_credentials" -H "Content-Type:application/x-www-form-urlencoded" https://<IS_HOST>:<IS_HTTPS_PORT>/oauth2/token
```
Example:
```
curl -u PoEgXP6uVO45IsENRngDXj5Au5Ya:eKsw6z8CtOJVBtrOWvhRWL4TUCga -k -d "grant_type=client_credentials" -H "Content-Type:application/x-www-form-urlencoded" https://localhost:9443/oauth2/token
```
In response, the self-contained JWT access token will be returned as shown below.
```
{
"access_token": "eyJ4NXQiOiJOVEF4Wm1NeE5ETXlaRGczTVRVMVpHTTBNekV6T0RKaFpXSTRORE5sWkRVMU9HRmtOakZpTVEiLCJraWQiOiJOVEF4Wm1NeE5ETXlaRGczTVRVMVpHTTBNekV6T0RKaFpXSTRORE5sWkRVMU9HRmtOakZpTVEiLCJhbGciOiJSUzI1NiJ9.eyJhdWQiOiJQb0VnWFA2dVZPNDVJc0VOUm5nRFhqNUF1NVlhIiwiYXpwIjoiUG9FZ1hQNnVWTzQ1SXNFTlJuZ0RYajVBdTVZYSIsImlzcyI6Imh0dHBzOlwvXC9sb2NhbGhvc3Q6OTQ0M1wvb2F1dGgyXC90b2tlbiIsImV4cCI6MTUzNDg5MTc3OCwiaWF0IjoxNTM0ODg4MTc4LCJqdGkiOiIxODQ0MzI5Yy1kNjVhLTQ4YTMtODIyOC05ZGY3M2ZlODNkNTYifQ.ELZ8ujk2Xp9xTGgMqnCa5ehuimaAPXWlSCW5QeBbTJIT4M5OB_2XEVIV6p89kftjUdKu50oiYe4SbfrxmLm6NGSGd2qxkjzJK3SRKqsrmVWEn19juj8fz1neKtUdXVHuSZu6ws_bMDy4f_9hN2Jv9dFnkoyeNT54r4jSTJ4A2FzN2rkiURheVVsc8qlm8O7g64Az-5h4UGryyXU4zsnjDCBKYk9jdbEpcUskrFMYhuUlj1RWSASiGhHHHDU5dTRqHkVLIItfG48k_fb-ehU60T7EFWH1JBdNjOxM9oN_yb0hGwOjLUyCUJO_Y7xcd5F4dZzrBg8LffFmvJ09wzHNtQ",
"token_type": "Bearer",
"expires_in": 3600
}
```
### 4. JWT Claims
The access token received is a signed JSON Web Token (JWT). Use a JWT decoder to decode the access token to access the payload of the token that includes following JWT claims:
|Claim Name|Type|Claim Value|
|:--:|:--:|:--:|
|iss| string | The issuer of the JWT. The '> Identity Provider Entity Id ' value of the OAuth2/OpenID Connect Inbound Authentication configuration of the Resident Identity Provider is returned here. |
|aud| string array | The token audience list. The client identifier of the OAuth clients that the JWT is intended for, is sent herewith. |
|azp| string | The authorized party for which the token is issued to. The client identifier of the OAuth client that the token is issued for, is sent herewith. |
|iat| integer | The token issue time. |
|exp| integer | The token expiration time. |
|jti| string | Unique identifier for the JWT token. |
Using the above `access_token` we can perform an STS request to Minio to get temporary credentials for Minio API operations. Minio STS API uses [JSON Web Key Set Endpoint](https://docs.wso2.com/display/IS541/JSON+Web+Key+Set+Endpoint) to validate if JWT is valid and is properly signed.
### 5. Setup Minio with JWKS URL
Minio server expects environment variable for JWKS url as `MINIO_IAM_JWKS_URL`, this environment variable takes a single entry.
```
export MINIO_IAM_JWKS_URL=https://localhost:9443/oauth2/jwks
minio server /mnt/data
```
Assuming that Minio server is configured to support STS API by following the doc [Minio STS Quickstart Guide](https://docs.minio.io/docs/minio-sts-quickstart-guide), execute the following command to temporary credentials from Minio server.
```
go run full-example.go -cid PoEgXP6uVO45IsENRngDXj5Au5Ya -csec eKsw6z8CtOJVBtrOWvhRWL4TUCga
##### Credentials
{
"accessKey": "IRBLVDGN5QGMDCMO1X8V",
"secretKey": "KzS3UZKE7xqNdtRbKyfcWgxBS6P1G4kwZn4DXKuY",
"expiration": "2018-08-21T15:49:38-07:00",
"sessionToken": "eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJhY2Nlc3NLZXkiOiJJUkJMVkRHTjVRR01EQ01PMVg4ViIsImF1ZCI6IlBvRWdYUDZ1Vk80NUlzRU5SbmdEWGo1QXU1WWEiLCJhenAiOiJQb0VnWFA2dVZPNDVJc0VOUm5nRFhqNUF1NVlhIiwiZXhwIjoxNTM0ODkxNzc4LCJpYXQiOjE1MzQ4ODgxNzgsImlzcyI6Imh0dHBzOi8vbG9jYWxob3N0Ojk0NDMvb2F1dGgyL3Rva2VuIiwianRpIjoiMTg0NDMyOWMtZDY1YS00OGEzLTgyMjgtOWRmNzNmZTgzZDU2In0.4rKsZ8VkZnIS_ALzfTJ9UbEKPFlQVvIyuHw6AWTJcDFDVgQA2ooQHmH9wUDnhXBi1M7o8yWJ47DXP-TLPhwCgQ"
}
```
## Explore Further
- [Minio STS Quickstart Guide](https://docs.minio.io/docs/minio-sts-quickstart-guide)
- [The Minio documentation website](https://docs.minio.io)