Build Server Side Authentication in Grails with OAuth 2.0 and Okta

John Ruggentaler

@mattraible thanks the redirect URI was redirect_uri=http://localhost:8443/oauth2/okta/callback… but it needed to be redirect_uri=https://localhost:8443/oauth2/okta/callback… Next question, after I logged into Okta I was redirected to the Grails Spring Security default login page. According to the above article

After logging in, you’ll be redirected back to your Grails app, where you’ll see the screen that allows you to either register a new account or link your OAuth account to an existing user account.

but I am seeing the default Grails Login page and the URL is https://localhost:8443/oauth2/okta/callback?state=okta-secret-<#####>&error=access_denied&error_description=Policy+evaluation+failed+for+this+request%2C+please+check+the+policy+configurations. How should I check the policy for my user? FYI, I created the user I logged in with in or Okta staging/preview environment as we are currently using Okta and I am trying to migrate our Grails apps to authenticate using Okta.

I enabled logging and after I logged into Okta I see the following message in the log:

2021-06-10 11:19:01.513 ERROR — [nio-8443-exec-5] o.g.web.errors.GrailsExceptionResolver : OAuth2Exception occurred when processing request: [GET] /oauth2/okta/callback - parameters:
state: okta-secret-######
error: access_denied
error_description: Policy evaluation failed for this request, please check the policy configurations.
No AuthCode in callback for provider ‘okta’. Stacktrace follows:

Matt Raible

If you create a developer account at developer.okta.com/signup, you’ll get a “default” authorization server that has default policies that’ll work with this tutorial. If you don’t have a “default” authorization server under Security > API, I’m not sure how to fix things.

John Ruggentaler

If you don’t have a “default” authorization server under Security > API, I’m not sure how to fix things.


Yes, I have a default authorization server, where do I put the authorization server (application.yml authorizeUrl: <here> )?
https://uploads.disquscdn.c…

I put the authorization server in the application.yml with key authorizeUrl and clicked the secure controller and the response was the following JSON object. The authorization_endpoint from the JSON object matched what I had in application.yml authorizeUrl: previously.


{
“issuer”: “https://login-staging.<my domain=”" name=“”>.com/oauth2/default",
“authorization_endpoint”: “https://login-staging.<my domain=”" name=“”>.com/oauth2/default/v1/authorize",
“token_endpoint”: “https://login-staging.<my domain=”" name=“”>.com/oauth2/default/v1/token",
“registration_endpoint”: “https://login-staging.<my domain=”" name=“”>.com/oauth2/v1/clients/0oazag1wr4G49b66z0h7",
“jwks_uri”: “https://login-staging.<my domain=”" name=“”>.com/oauth2/default/v1/keys",
“response_types_supported”: [
“code”,
“token”,
“id_token”,
“code id_token”,
“code token”,
“id_token token”,
“code id_token token”
],
“response_modes_supported”: [
“query”,
“fragment”,
“form_post”,
“okta_post_message”
],
“grant_types_supported”: [
“authorization_code”,
“implicit”
],
“subject_types_supported”: [
“public”
],
“scopes_supported”: [
“cdi”,
“clientapi”,
“clinicalservices”,
“coding”,
“datafaceapi”,
“evaluationapi”,
“formsapi”,
“memberapi”,
“productapi”,
“providerapi”,
“routingapi”,
“scheduling”,
“schedulingapi”,
“travelapi”,
“openid”,
“profile”,
“email”,
“address”,
“phone”
],
“token_endpoint_auth_methods_supported”: [
“client_secret_basic”
],
“claims_supported”: [
“ver”,
“jti”,
“iss”,
“aud”,
“iat”,
“exp”,
“cid”,
“uid”,
“scp”,
“sub”
],
“code_challenge_methods_supported”: [
“S256”
],
“introspection_endpoint”: “https://login-staging.<my domain=”" name=“”>.com/oauth2/default/v1/introspect",
“introspection_endpoint_auth_methods_supported”: [
“client_secret_basic”
],
“revocation_endpoint”: “https://login-staging.<my domain=”" name=“”>.com/oauth2/default/v1/revoke",
“revocation_endpoint_auth_methods_supported”: [
“client_secret_basic”
],
“end_session_endpoint”: “https://login-staging.<my domain=”" name=“”>.com/oauth2/default/v1/logout",
“request_parameter_supported”: true,
“request_object_signing_alg_values_supported”: [
“HS256”,
“HS384”,
“HS512”
]
}

Where do we get the dependency

“spring.security.oauth2.okta:spring-security-oauth2-okta:0.1”

?
How to resolve

“could not find spring.security.oauth2.okta: spring-security-oauth-okta:0.1”

?

I can’t find it on maven central as well as jcenter or the default grails repo.
Can anyone share where to find that dependency is or is that tutorial now too old and that dependency is no longer used?

It looks like the plugins in question in this post were hosted on Bintray (which has been shut down).

Since the post is a couple of years old, it’s probably due for a refresh. I’ll add it to our todo list!

In the meantime, if your Grails application uses Spring, you can take a look at the Spring Security integration (assuming it supports Spring Sec 5.x+).

Otherwise, you can take a look at this technique (which works great for new apps too):

1 Like

Thank you very much. I will look into it.
I am working on a legacy Grails 2.4.5 application with Okta set up at the Enterprise level. A custom enterprise plugin dealing with OAuth, combining spring-security and Okta is being used.
I am trying to see how to have the front-end communicate with the back-end with Okta security.
So far, everything is redirected to the okta v1/authorize, however I am not sure what other configurations need to be done to get the data back and have the request being redirected to the actual original request.

Just testing the created rest-endpoints secured with Okta by themselves, I can see them inside the browser, but can’t even see or access the data inside the IntelliJ terminal of the project with “curl -H “Accept:application/json” -i -v http://localhost:8090/application/api/users” or inside Postman. I am trying to find out what other requirements are needed to be added inside the headers or somewhere else.

I am hoping these tutorials will help point me in the right direction.

Thank you very much

1 Like

How would we use that solution to do the current tutorial?

Hi,

How to integrate with custom loginp age and validate with okta without saving to db

Hey this is a bit of a hail mary, but this tutorial may be the only way for my company to get a crucial application integrated with our existing Okta setup (We’re stuck on Grails 3.3.3, so Okta Spring Starter won’t work). I know that the plugin is no longer hosted on bintray, and so I have compiled it into a jar and put it in my build.gradle in a libs\ directory on just a standalone Grails 3.3.3 app as a proof of concept, but now I am running into an error when attempting to navigate to my login page:

2023-08-20 23:31:02.666 ERROR --- [nio-8080-exec-9] .g.p.s.o.SpringSecurityOauth2BaseService : There is no providerService for okta
2023-08-20 23:31:02.680 ERROR --- [nio-8080-exec-9] o.g.web.errors.GrailsExceptionResolver   : OAuth2Exception occurred when processing request: [GET] /springSecurityOAuth2/authenticate - parameters:
provider: okta
No provider 'okta'. Stacktrace follows:

java.lang.reflect.InvocationTargetException: null

My first guess was incorrect setup of my application.yml, but it seems like all my indentations are correct, is this way of implementing your plugin a valid technique? Should I be altering my approach? Thank you!