Problem logging with OKTA Production for "/oauth2/default/v1/authorize"

167 Views Asked by At

In dev account I'm using "/oauth2/default/v1/authorize" and everything works fine.

However, using this URI with our production account redirects me to a 400 error page with the message "The requested feature is not enabled in this environment".

I saw where some people have said to remove the "http://{yourOktaOrg}/oauth2/default" from the URI, which I tried, but got a 404 error.

Then I got another ref saying removing "default" will not led you to paid feature. This help me to bypass login and redirect it to the callback handler. But further I am using exchange code API "http://{yourOktaOrg}/oauth2/v1/token" which will help me to get IdToken.

because of not getting token verification get failed and I am not able to save session.

I tried with "http://{yourOktaOrg}/v1/token"

Any help would be greatly appreciated.

If I don't want to go for paid service will that be possible ?

Type of Application: Server-side (golang),

here is my code:

package middleware

import (
    "bytes"
    "crypto/rand"
    "encoding/base64"
    "encoding/hex"
    "encoding/json"
    "fmt"
    "io/ioutil"
    "log"
    "net/http"

    "github.com/gorilla/sessions"
    verifier "github.com/okta/okta-jwt-verifier-golang"
)

type Exchange struct {
    Error            string `json:"error,omitempty"`
    ErrorDescription string `json:"error_description,omitempty"`
    AccessToken      string `json:"access_token,omitempty"`
    TokenType        string `json:"token_type,omitempty"`
    ExpiresIn        int    `json:"expires_in,omitempty"`
    Scope            string `json:"scope,omitempty"`
    IdToken          string `json:"id_token,omitempty"`
}

type OKTADetails struct {
    CLIENT_ID     string `json:"client_id"`
    CLIENT_SECRET string `json:"client_secret"`
    ISSUER        string `json:"issuer"`
    RedirectURI   string `json:"redirect_uri"`
}

var (
    sessionStore = sessions.NewCookieStore([]byte("okta-hosted-login-session-store"))
    state        = generateState()
    nonce        = "NonceNotSetYet"
    okta         OKTADetails
)

func GetOKTADetails(client_id, client_secret, issuer, redirect_uri string) {
    okta.CLIENT_ID = client_id
    okta.CLIENT_SECRET = client_secret
    okta.ISSUER = issuer
    okta.RedirectURI = redirect_uri
}

func generateState() string {
    // Generate a random byte array for state paramter
    b := make([]byte, 16)
    rand.Read(b)
    return hex.EncodeToString(b)
}

func GenerateNonce() (string, error) {
    nonceBytes := make([]byte, 32)
    _, err := rand.Read(nonceBytes)
    if err != nil {
        return "", fmt.Errorf("could not generate nonce")
    }
    return base64.URLEncoding.EncodeToString(nonceBytes), nil
}

func LoginHandler(w http.ResponseWriter, r *http.Request) {
    w.Header().Add("Cache-Control", "no-cache") // See https://github.com/okta/samples-golang/issues/20

    nonce, _ = GenerateNonce()
    var redirectPath string

    q := r.URL.Query()
    q.Add("client_id", okta.CLIENT_ID)
    q.Add("response_type", "code")
    q.Add("response_mode", "query")
    q.Add("scope", "openid profile email")
    q.Add("redirect_uri", okta.RedirectURI)
    q.Add("state", state)
    q.Add("nonce", nonce)

    redirectPath = okta.ISSUER + "/v1/authorize?" + q.Encode()

    http.Redirect(w, r, redirectPath, http.StatusFound)
}

func AuthCodeCallbackHandler(w http.ResponseWriter, r *http.Request) {
    // Check the state that was returned in the query string is the same as the above state
    if r.URL.Query().Get("state") != state {
        fmt.Fprintln(w, "The state was not as expected")
        return
    }
    // Make sure the code was provided
    if r.URL.Query().Get("code") == "" {
        fmt.Fprintln(w, "The code was not returned or is not accessible")
        return
    }

    exchange := exchangeCode(r.URL.Query().Get("code"), r)
    if exchange.Error != "" {
        fmt.Println(exchange.Error)
        fmt.Println(exchange.ErrorDescription)
        return
    }

    session, err := sessionStore.Get(r, "okta-hosted-login-session-store")
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
    }

    _, verificationError := verifyToken(exchange.IdToken)

    if verificationError != nil {
        fmt.Println(verificationError)
    }

    if verificationError == nil {
        session.Values["id_token"] = exchange.IdToken
        session.Values["access_token"] = exchange.AccessToken

        session.Save(r, w)
    }

    http.Redirect(w, r, "/", http.StatusFound)
}

func LogoutHandler(w http.ResponseWriter, r *http.Request) {
    session, err := sessionStore.Get(r, "okta-hosted-login-session-store")
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
    }

    delete(session.Values, "id_token")
    delete(session.Values, "access_token")

    session.Save(r, w)

    http.Redirect(w, r, "/", http.StatusFound)
}

func exchangeCode(code string, r *http.Request) Exchange {
    authHeader := base64.StdEncoding.EncodeToString(
        []byte(okta.CLIENT_ID + ":" + okta.CLIENT_SECRET))

    q := r.URL.Query()
    q.Add("grant_type", "authorization_code")
    q.Set("code", code)
    q.Add("redirect_uri", okta.RedirectURI)

    url := okta.ISSUER + "/v1/token?" + q.Encode()

    req, _ := http.NewRequest("POST", url, bytes.NewReader([]byte("")))
    h := req.Header
    h.Add("Authorization", "Basic "+authHeader)
    h.Add("Accept", "application/json")
    h.Add("Content-Type", "application/x-www-form-urlencoded")
    h.Add("Connection", "close")
    h.Add("Content-Length", "0")

    client := &http.Client{}
    resp, _ := client.Do(req)
    body, _ := ioutil.ReadAll(resp.Body)
    defer resp.Body.Close()
    var exchange Exchange
    json.Unmarshal(body, &exchange)

    return exchange
}

func IsAuthenticated(r *http.Request) bool {
    session, err := sessionStore.Get(r, "okta-hosted-login-session-store")

    if err != nil || session.Values["id_token"] == nil || session.Values["id_token"] == "" {
        return false
    }

    return true
}

func verifyToken(t string) (*verifier.Jwt, error) {
    tv := map[string]string{}
    tv["nonce"] = nonce
    tv["aud"] = okta.CLIENT_ID
    jv := verifier.JwtVerifier{
        Issuer:           okta.ISSUER,
        ClaimsToValidate: tv,
    }

    result, err := jv.New().VerifyIdToken(t)
    if err != nil {
        return nil, fmt.Errorf("%s", err)
    }

    if result != nil {
        return result, nil
    }

    return nil, fmt.Errorf("token could not be verified: %s", "")
}

0

There are 0 best solutions below