Okta-vue-books-pwa-example not working

I am building an application on VueJS with Typescript using Okta as the authentication provider. I cloned the okta-vue-books-pwa-example repo locally, installed the packages.

I then created a new app on my Okta dev account:

I modified the issuer and client_id fields in src/router.ts. And ran the command npm run serve.

On localhost:8080 I clicked on “Login” and got this error message:

I haven’t modified anything in the source files except for the two fields. Any thoughts on that? Could you try doing the same?

Checking Implicit in the app’s settings makes it work.

Can somebody explain me what’s the difference between the two options: Authorization Code and Implicit?

Thank you in advance.

Hi Ivan:

It should work with authorization code. I’ll take a look and get back to you.

In the meantime, the Implicit Flow is essentially deprecated. Here’s a good reference: https://developer.okta.com/blog/2019/05/01/is-the-oauth-implicit-flow-dead

The Implicit flow returns tokens directly in the browser’s address bar. This is problematic for a number of reasons, not the least of which is access token interception by misbehaving browser extensions or Javascript on the page. The implicit flow was created at a time when both browsers and service providers had more limitations.

The Authorization Code Flow, by contrast, has a “token exchange” step where a code delivered via the browser’s address bar is then exchanged for a token using an HTTP POST. The token comes back in the response, thus avoiding it passing through the browser’s address bar.

For SPA apps, there’s an extension called PKCE (Proof Key for Code Exchange) that enables the use of the Authorization Code flow in untrusted/public environments (like the browser or mobile apps).

1 Like

One other thing to check here: You posted the settings of your application, but NOT the authorization server. In your Okta Admin Console, navigate to: API > Authorization Servers. Click default. On the Access Policies tab, click the pencil next to Default Policy Rule and make sure that Authorization Code is checked. It should be by default, but having this unchecked could produce the result you’re seeing.

I ran through the example and got the same results you did. The issue was that the version for the okta-vue-sdk was out of date.

I’ve updated the repo here: GitHub - oktadev/okta-vue-books-pwa-example: A Progressive Web Application with Vue and TypeScript

If you use that version as your base, it should now work with the authorization code + pkce flow automatically.

If you take a look in your browser’s network calls in the developer console, you’ll see both a GET to the /authorization endpoint and then, later on, a POST to the /token endpoint. If you look at the response from that request, you’ll see the tokens being returned.

1 Like

Hi, thank you for your response. I have updated the package’s version and it works fine now with only Authorization Code checked!

This repo gives me a good view of how I can secure an SPA with Okta. I have also read a few different articles on developer.okta.com namely OIDC Primer, Validiting access tokens in NodeJS to learn how to secure an API.

I have an SPA and a backend REST API and looking to secure them with Okta. What I haven’t yet wrapped my head around is how those two come together. I know I can secure requests from one machine to another with a client_id, client_secret pair (by requesting an access_token to the auth server). However those requests are not dependent on the user actually being logged in on the SPA since the access token only depends on the two client keys stored on the SPA.

Here’s a simple use case: a page where only authorized users can make a request to the API. I can restrict access by making the user log on the SPA. The request would then be made securely from the SPA to the API endpoint using the client_id and client_secret. However, how would the backend know about the user’s identity? Is that where scopes come into play?

Ok let me try clear up a few things for you :slight_smile: A token contains information about a user, also called claims. It can contain things like This user his first name is Bob and his email is bob@company.org.

Scopes define what kind of claims you are requesting of a certain user. For example if I make a request with the scope email I am saying “hey I want to know the email of the user”. If Bob logs in then the token will contain the claim email with Bob’s email.

There are many ways on getting a token but the most frequent one is Authorization Code Flow. Here you request a code, the server gives one back, you exchange this code in the backend for a token. When decoded you get claims about the user.

The way you protect resources on your API/App is by saying I want a valid token from authorization server X (Okta in our case). You validate the token (again there are more ways in validating a token). IF everything is ok you can read the claims.
Another simple example. Bob is part of the Admin group in Okta. We have a scope called groups which returns what group the user is a part of. We request a token with the Scope ‘groups’, we get a token back with the claim that Bob is an Admin. On our application that we protect we must have a valid token and have a claim of groups that says ‘Admin’.

The backend knows more about the user by reading the claims of the token.

Okta has a good talk that explains the very basics of oAuth here - https://www.youtube.com/watch?v=996OiexHze0

Thank you very much for your detailed explanation. I haven’t yet watched the video. However based on your example here’s what I understood:

IdP: We create an app of type “Web” on Okta.

SPA: Auth config on SPA. This is the first call to Okta on /authorize.

const config = {
  clientId: '${app clientId}',
  issuer: 'https://${oktaDomain}/oauth2/default/v1/authorize',
  redirectUri: 'http://localhost:8080/authorization-code/callback',
  scopes: ['openid', 'group', 'email'],
  response_type: 'code'
};

This SPA only has the client_id.

Backend: Has the (client_id, client_secret) pair stored in order to validate the incoming tokens.

If I understand correctly, here’s how the Auth Code flow goes:

  1. The user visits the SPA and is redirected to the IdP’s sign-in page;
  2. The IdP redirects the user to the SPA with an authorisation code;
  3. SPA sends the authorization code to the /login endpoint on IdP;
  4. IdP validates the authorization code and sends the access_token (which contains the claims initially requested by the SPA);
  5. When the SPA makes requests to the backend, it sends the access_token;
  6. The backend receives the token, can validate it through Okta and can then access the claims.

Hi @Ivan

I want to emphasize that we are using the authorization code flow here, SPA is usually associated implicit flow but let’s park that idea for now since you have a backend. I see in your first post that it is expecting PKCE, this is more secure but adds a layer of complexity. Try change it to just client id and secret.

IdP: also known as the identity provider is Okta and yes we create an application in Okta which is used to identify clients (like your SPA app).

The auth config looks good! what you basically configure there is hey I am this client, I want to request these scopes and return it in this format.

Backend:
It should hold the client id and secret. These 2 are used to make requests to the authorization server. (Okta). When you send a request you need to authenticate your client, remember that app you created in Okta? If you provide the client id and secret of that created app then Okta knows who is trying to authenticate and it can do it’s magic by checking a few security settings and send back a code.

Okta will send back an authorization code to your callback url. Your backend takes this code and exchanges it for an access token by calling the /token endpoint of the authorization server. To avoid any confusion here since I used code and access token. They are different things. A code is actually pretty meaningful, it is a random string but to make it secure you use this code and swap it for a token in the backend. It is the token that contains user context.

So the flow looks as follows

  1. You make an authorization request by calling /authorize endpoint. (from your SPA app).
  2. This usually results in a redirect to the IdP (Okta) where the user has to authenticate.
  3. Okta sends back a code to your callback url
  4. Your backend takes this code and exchanges it for a token
  5. Your backend now has a token
  6. Use token to call protected resource (this can be the same app or it could be a different API).
  7. Protected resource validates if the token is valid (at this stage it can do extra checks by decoding it and checking the claims).

oAuth can be really confusing at first so if you have any more questions let me know. I would be happy to help :slight_smile:

I really appreciate your help, thank you!

On step

  1. Your backend takes this code and exchanges it for a token

Isn’t that the SPA’s job to get the token and use it in order to make API calls to my backend?

On Okta, it seems that a “Web” app and a “SPA” app give two different setups. The first provides a client_id and client_secret while the second provides a client_id and uses PKCE for client auth (I haven’t looked into PKCE, but will definitely).

I was about to use the /authorize endpoint but this ended up not working. Somehow the SPA doesn’t redirect to the login page and okta-vue returns an error.

So I decided to use the implicit flow instead. If I’m only using “Authorization Code” as the allowed grant type doesn’t that mean it’s actually using the implicit flow? It definitely qualifies as being Auth Code Flow since there’s a code request then a token request. It’s quite misleading since the redirect endpoint is called implicit/callback…

Anyway here’s my current setup

{
  issuer: 'https://dev-{oktaDomaineId}.okta.com/oauth2/default',
  clientId: {clientId},
  redirectUri: window.location.origin + '/implicit/callback',
  scopes: ['openid', 'email'],
  responseType: ['code']
}

This seems to work. When I visit the SPA, a button allows me to trigger a okta-vue function which gets the code. I can login on the Okta hosted page, then I am redirected to implicit/callback where okta-vue captures the code and redirects again to the main page. From there I can get the token and use it to make API calls to my backend. I can also access the user’s claims from the token.

I already have the API setup with jwt-verifier. I will try to make a call from the SPA to the backend and share my progress. Also I’ll try to add PKCE into the flow.

Thank you again!

Hey Ivan,

Micah from Okta here again. I want to clear up a few things posted along the way on this thread.

  1. The purpose of the SPA app using the Authorization Code + PKCE flow is to get BOTH and access token and id token to the SPA app more securely then can be done with the Implicit flow. If you’re using our tools (as you are), there is no additional complexity because the library manages the token exchange behind the scenes for you. TL;DR - the implicit flow should NOT be used anymore as it has fundamental security issues that are addressed by PKCE.

  2. The MOST secure footing would be to use the traditional Authorization Code flow managed completely by the backend. The downside is that this would require your application redirecting to Okta for users to authenticate and then Okta would redirect back to your application. This can be mitigated by customizing the look-and-feel of the Okta hosted authentication page. You can even setup a custom domain, so the redirect is less noticeable to your users and they have more confidence in your app, since the base domain doesn’t change. What I mean by this is that if your domain is: mydomain.com, you could have login.mydomain.com be the Okta hosted login page. The upside is that your application never handles the user’s credentials, which was one of the major original goals of OAuth. In this scenario, your SPA app would never get any tokens directly. You would use the built in session capabilities of the framework you’re using and when you need to make an api call, the back-end would have the access token in the session.

  3. If it’s a requirement that your SPA app make API calls directly, then your SPA app will have to have the access token. In this case, you’d want to use the Authorization Code + PKCE flow. Your SPA app could then make API calls directly with the access token it obtains.

Hope this Helps!

-Micah

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