List users and groups with and administrator read only account with no login page prompted

Hello,

I need to list users and groups on a backend microservice that will call the Okta Api but I can’t use an API Token with SDK (simplest way) and I can’t use a key pair with client credentials too (Information Security area policies).

I would like to get a token for an administrator read only account passing username/password to get the token with the roles okta.users.read/okta.groups.read.

My application type is web.

I did something similar on Postman following this procedure describe on this page: Get an access token and make a request | Okta Developer

Using Postman a login page was prompted to me and I put username and password. I can’t do that in my code because I trying to do a microservice that will call the okta users/groups api with a token generated by an oauth2 flow with the caveats that I described above.

I blowing up my mind with this issue because I didn’t found any oauth2 flow that works this way.

I appreciate any tip. I am using spring boot application.

There is a trick for that:

  1. You run /authn request with your username and password. On SUCCESS you’ll get sessionToken back
  2. You run /authorize request with ...prompt=none&sessionToken=<your_token>&response_type=token... and all other parameters matching your OIDC app configuration (client_id, scope, redirect_uri). If all was success, then you’ll get a redirection response with URL having access token in it.

If your app is PKCE or web you’ll have to do an extra step with code exchange. I haven’t tried it myself, but you can try and let us all know if it also works for you

Hello Phi1ipp,

The application type is web. I did what you suggested but when I called the /authorize request I got in response a page like this:

Login with OAuth 2.0

[invalid_request]
https://dev-1234567890.okta.com/oauth2/default

I think someone had this situation before. I can research something similar on github, but I don’t know exactly what I looking for, how do we named this flow? How would you do this research?

you need to send correct values to your endpoints. I just ran my example with “web” flow, and all worked just fine

  1. call to /autorize → you get the code
  2. call to /token with the code from #1 and authorization from client id/secret → you get your token
package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"net/http"
	"net/url"
	"regexp"
	"strings"
)

const baseUrl = "https://dev-xxxxx.oktapreview.com"
const client_secret = "<app client secret>"
const client_id = "<app client id>"
const redirect_uri = "http://localhost:8080/cb.html"
const scope = "openid"
const username = "<your username>"
const password = "<your password>"

func main() {
	fmt.Println("starting")

	vals := map[string]string{"username": username, "password": password}
	json_data, err := json.Marshal(vals)

	if err != nil {
		fmt.Println("error encoding json")
		return
	}

	resp, err := http.Post(fmt.Sprintf("%s/api/v1/authn", baseUrl), "application/json", bytes.NewBuffer(json_data))

	if err != nil {
		fmt.Println("error postin")
		return
	}

	if resp.StatusCode != 200 {
		fmt.Println("not 200")
		return
	}

	var body map[string]interface{}

	err = json.NewDecoder(resp.Body).Decode(&body)
	if err != nil {
		fmt.Println("error parsing response body")
		return
	}

	var sessionToken string = body["sessionToken"].(string)
	fmt.Println("stateToken: " + sessionToken)

	authUrl :=
		fmt.Sprintf("%s/oauth2/default/v1/authorize?client_id=%s&redirect_uri=%s&sessionToken=%s&scope=%s",
			baseUrl, client_id, redirect_uri, sessionToken, scope)
	const_part := "&prompt=none&response_type=code&response_mode&nonce=123&state=123"

	client := &http.Client {
		CheckRedirect: func(req *http.Request, via []*http.Request) error {
			return http.ErrUseLastResponse
		},
	}

	req, err := http.NewRequest("GET", authUrl + const_part, nil)

	resp, err = client.Do(req)

	if err != nil {
		fmt.Println("error sending GET")
		fmt.Println(err)
	}

	if resp.StatusCode != 302 {
		fmt.Println("response is not 302")
		return
	}

	fmt.Println("response is ", resp.Header["Location"][0])
	r := regexp.MustCompile(`code=(?P<code>[^&]+)`)

	m := r.FindStringSubmatch(resp.Header["Location"][0])
	code := m[1]
	fmt.Println("code:", code)

	urlToken := fmt.Sprintf("%v/oauth2/default/v1/token", baseUrl)
	formData := url.Values{
		"code":{code},
		"grant_type":{"authorization_code"},
		"redirect_uri": {redirect_uri},
	}

	client = &http.Client{}
	req, err = http.NewRequest("POST", urlToken, strings.NewReader(formData.Encode()))

	if err != nil {
		fmt.Println("error prepping req to /token")
		fmt.Println(err)
	}

	req.SetBasicAuth(client_id, client_secret)
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")

	resp, err = client.Do(req)

	if err != nil {
		fmt.Println("error posting data to /token")
		fmt.Println(err)
	}

	err = json.NewDecoder(resp.Body).Decode(&body)
	if err != nil {
		fmt.Println("error decoding body from /token")
		fmt.Println(err)
	}

	fmt.Println("access_token:", body["access_token"])
}

Hello @phi1ipp ,

Using your code I only changed to the Org authorization server (without “default”) to got a token for the scopes okta.users.read/okta.groups.read and everything worked fine.

I appreciated your help. Really impressive the Okta Team support.

Thank you! I was a long time trying to solve this challenge and your help was amazing.

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.