On this page
Sign users in to your web app using the redirect model
Add a user sign-in flow to a server-side web app with Okta's redirect model (opens new window).
Learning outcomes
- Implement a simple redirect to an Okta-hosted sign-in page.
- Configure a server-side web app to use Okta.
- Test that users can sign in and sign out.
- Define which parts of an app require authentication and which don't.
What you need
Sample code
Overview
The easiest and most secure way to add a user sign-in flow to your server-side web app is to use an Okta-hosted Sign-In Widget. When a user attempts to sign in, the app redirects them to the widget hosted on an Okta web page. After they've signed in successfully, Okta redirects them back to the app. This is known as the redirect authentication deployment model.
Note: To use the redirect model in a single-page application (SPA), see Sign users in to your SPA using the redirect model. To use the redirect model in a mobile app, see Sign users in to your mobile app using the redirect model.
In this quickstart, you:
- Create an app integration in the Admin Console.
- Create and configure a new web app to use Okta.
- Test that a user can sign in and sign out.
- Configure different levels of access for specific areas of the site.
Tip: You need your Okta org domain to follow this tutorial. It looks like
dev-123456.okta.com
. See Find your Okta domain. Where you see{yourOktaDomain}
in this guide, replace it with your Okta domain.
Create an app integration in the Admin Console
An app integration represents your app in your Okta org. Use it to configure how your app connects with Okta services.
To create an app integration for your app:
Open the Admin Console for your org.
- Sign in to your Okta organization (opens new window) with your administrator account.
- Click Admin in the upper-right corner of the page.
Go to Applications > Applications to view the current app integrations.
Click Create App Integration.
Select OIDC - OpenID Connect as the Sign-in method.
Select Web Application as the Application type, then click Next.
Note: You can break the sign-in or sign-out flows for your app if you choose the wrong app type.
Enter an App integration name. For example, My first web application.
Enter the callback URLs for the local development of your app.
- Enter
- Enter
Note: The values suggested here are those used in the sample app.
- Enter
Select Allow everyone in your organization to access for Controlled access.
Click Save to create the app integration.
The configuration page for the new app integration appears. Keep this page open.
Note: For a complete guide to all the options not explained in this guide, see Create OIDC app integrations (opens new window).
Note your client ID and client secret
Make a note of two values that you use to configure your web app. Both are in the configuration pane for the app integration that you've created:
- Client ID: Found on the General tab in the Client Credentials section.
- Client Secret: Found on the General tab in the Client Credentials section.
Moving on, where you see {clientId}
and {clientSecret}
in this guide, replace them with your client ID and client secret.
Create and configure a new web app to use Okta
Now that you have created the app integration and noted the configuration settings, complete the following steps:
- Create a web app.
- Add the required packages to your app
- Configure your app to use Okta
- Add the pages and logic for a user to sign in and sign out
Create a web app
Add the required packages to your app
Configure your app to use Okta
Earlier you noted the client ID and client secret values generated for your app integration. Add these and your Okta domain to your app's configuration.
Add the pages and logic for a user to sign in and sign out
A user can start the sign-in process by:
- Clicking a sign-in link or button
- Trying to access a protected page, such as their profile page.
In both cases, the app redirects the browser to the Okta-hosted sign-in page. See Redirect to the sign-in page.
After the user signs in, Okta redirects the browser to the sign-in redirect URI that you entered earlier. Similarly, after a user signs out, Okta redirects the browser to the sign-out redirect URI. Both sign-in and sign-out redirect URIs are called callback routes. Users don't see callback routes, and they aren't the user's final destination. However, your app does need to implement them. See Define a callback route.
After the user signs in, Okta returns some of their profile information to your app. The default profile items (called claims) returned by Okta include the user's email address, name, and preferred username. These are sent in an ID token (opens new window) as part of the redirect to the sign-in redirect URL. See Get the user's information.
Redirect to the sign-in page
Note: To customize the Okta sign-in form, see Style the Okta-hosted Sign-In Widget.
Define a callback route
Get the user's information
After a user has signed in, the application receives ID and access tokens from Okta and keeps them in session storage. In this section, you create a simple profile page that uses an access token to query for and display a user's basic information.
Add a route handler for
/profile
tomain()
inmain.go
:http.HandleFunc("/profile", ProfileHandler)
Define the handler function:
func ProfileHandler(w http.ResponseWriter, r *http.Request) { type customData struct { Profile map[string]string IsAuthenticated bool } data := customData{ Profile: getProfileData(r), IsAuthenticated: isAuthenticated(r), } tpl.ExecuteTemplate(w, "profile.gohtml", data) }
Add the following function to request the user's info upon a successful sign-in flow:
func getProfileData(r *http.Request) map[string]string { m := make(map[string]string) session, err := sessionStore.Get(r, "okta-hosted-signin-session-store") if err != nil || session.Values["access_token"] == nil || session.Values["access_token"] == "" { return m } reqUrl := os.Getenv("ISSUER") + "/v1/userinfo" req, _ := http.NewRequest("GET", reqUrl, bytes.NewReader([]byte(""))) h := req.Header h.Add("Authorization", "Bearer "+session.Values["access_token"].(string)) h.Add("Accept", "application/json") client := &http.Client{} resp, _ := client.Do(req) body, _ := io.ReadAll(resp.Body) defer resp.Body.Close() json.Unmarshal(body, &m) return m }
Finally, create
templates\profile.gohtml
to display the user's information:{{template "header" .}} <div> <h2>My Profile</h2> <p>Hello, <span>{{ .Profile.name }}</span>. </p> </div> <table> <thead> <tr> <th>Claim</th> <th>Value</th> </tr> </thead> <tbody> {{ range $key, $value := .Profile }} <tr> <td>{{ $key }}</td> <td id="claim-{{$key}}">{{ $value }}</td> </tr> {{ end }} </tbody> </table> </div> {{template "footer"}}
Note: The claims that you see may differ depending on the scopes requested by your app. See Configure your app to use Okta and Scopes (opens new window).
Test that a user can sign in and sign out
Your site now has enough content to sign a user in with Okta, prove they've signed in, and sign them out. Test it by starting your server and signing a user in.
Run the following command to start the go app:
go run main.go
Open a browser and go to
http://localhost:8080
.Click Sign In. The browser redirects you to Okta to sign in using the Sign-In Widget.
After you sign in, click Profile. The profile page displays the user information returned by Okta.
Click Sign Out. The browser returns you to the home page.
Note: If you're signed in as an administrator in the same browser already, it displays your name. You can open an incognito window and create a test user in the Admin Console to use.
Configure different levels of access for specific areas of the site
Your app can require authentication for the entire site or just for specific routes. Routes that don't require authentication are accessible without signing in, which is also called anonymous access.
Require authentication for everything
Some apps require user authentication for all routes, for example a company intranet.
You can use a middleware function to protect any endpoint so only authenticated users can access it.
Add a function
IsAuthenticated()
inmain.go
to check the user's status:func isAuthenticated(r *http.Request) bool { session, err := sessionStore.Get(r, "okta-hosted-signin-session-store") if err != nil || session.Values["id_token"] == nil || session.Values["id_token"] == "" { return false } return true }
Add a middleware function that wraps
IsAuthenticated()
:func middleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if !isAuthenticated(c.Request) { log.Printf("Unauthorized route: %s", c.Request.URL.Path) c.Redirect(http.StatusFound, "/login") return } next.ServeHTTP(w, r) }) }
Change your route handler to wrap the handler function in the middleware:
http.Handle("/profile", middleware(http.HandlerFund(ProfileHandler)))
Require authentication for a specific route
Your website may have a protected portion that is only available to authenticated users.
You can also use the isAuthenticated()
method to check if a user is authenticated and show more data within a page. For example, home.gohtml
shows Sign in or Sign out according to the user's status.
{{if .IsAuthenticated}}
<div>
<p>Hello <span>{{.Profile.name}}</span>!</p>
<p>Visit your <a href="profile">Profile</a> page.</p>
<form method="post" action="/signout">
<button id="signout-button" type="submit">Sign out</button>
</form>
</div>
{{else}}
<div>
<p>Hello!</p>
<form method="get" action="/signin">
<button id="signin-button" type="submit">Sign in</button>
</form>
{{end}}
HomeHandler()
calls isAuthenticated()
to populate its data model:
func HomeHandler(w http.ResponseWriter, r *http.Request) {
type customData struct {
Profile map[string]string
IsAuthenticated bool
}
data := customData{
Profile: getProfileData(r),
IsAuthenticated: isAuthenticated(r),
}
tpl.ExecuteTemplate(w, "home.gohtml", data)
}
Allow anonymous access
Your website may enable anonymous access for some content but require a user to sign in for other content or to take some other action. For example, an ecommerce site might allow a user to browse anonymously and add items to a cart, but require a user to sign in for checkout and payment.
By default all the routes declared are public unless modified with middleware and hence can be accessed anonymously.
Next steps
- Protect your API endpoints.
- Custom domain and email address
- Style the Okta-hosted Sign-In Widget.
- Sign users in to your mobile app using the redirect model
- Multi-tenant solutions
Go and Gin official docs:
- Gin Gonic documentation (opens new window)
- Getting started with Go and Gin (opens new window)
- Okta Golang Gin & Okta-Hosted Login Page Example (opens new window)
Okta Developer resources: