Laravel Sanctum API Token Security - laravel-sanctum

Hello great people of SO!
I hope you all have a great day!
First of all, I'm new to SPA, and I'm sorry if my english is bad
But I will try my best to explain what issue I have right now
I'm creating a simple SPA that use Sanctum API Token as Authentication and Vue as Front
After creating simple Auth mechanism (such: Route guard, errors, etc) of this SPA, a simple thought comes to my mind
What if I copy a token, then insert it to another browser, will the server Authenticate me?
Steps to produce:
First, I login to Brave browser, and server return the Authorization token, the token stored inside Brave localStorage, and Front-end part redirect me to '/home' route, everything works normal like simple authentication
Then, I opened Firefox browser, I put token and token_value inside localStorage, which I got before from logging in with Brave browser
I visited '/home' route, which is only for Authenticated users, and the server accept me.
I cannot find in documentation about this matter
How to solve this matter?

The Laravel docs state, "You should not use API tokens to authenticate your own first-party SPA. Instead, use Sanctum's built-in SPA authentication features".
You might want to read more between Tokens and Cookies for authentication here.
Token Authentication vs. Cookies
You would be authenticated anytime you send a request with a valid token. Doesn't matter which browser. It works on any medium that is able to make a request.
If it's a SPA, use Sanctum SPA authentication mechanisms.
Not sure if this answers your questions.

Related

Understanding the flow of OAuth2

I'm new to OAuth2 and I'm trying to understand the whole flow of things. For context, I'm thinking of making a web dashboard where users log in via Discord's OAuth2 API.
This is how I think the flow works based on my understanding so far:
User goes to my site and clicks a login link
My site redirects them to Discord with my client ID and a redirect URL #1 in the query string
Discord redirects them back to my site at redirect URL #1 with an authorisation code in the query string
My site takes this authorisation code and along with my client ID, client secret and redirect URL #2, uses all these to fetch an access token and refresh token from Discord
If I do get an access token, that means the user is now "logged in" (authorisation code worked)
My site finally redirects the user to a page and is now free to send requests to Discord's API with the access token, while saving the access token and refresh token. Just for example, say the page states their Discord username
I'm learning from this guide, and what confuses me is this code snippet from the guide. At line 5, it provides the redirect URL #2 mentioned above, in the query string. I'm not sure what it's for.
Also, I'm not very sure how to continue once I have the access token. If multiple users log in, I'd have multiple access tokens on hand. Say a user wants to access the page again, how do I uniquely identify them and know which access token to use to send requests to Discord's API? (for this example, the request would give me their username which I'd display on the page)
Yeah, I probably got a lot of concepts wrong. Any clarification would be greatly appreciated!
Edit: I've done more research into this, and found a much better guide here.
For my question about the second redirect URL, the examples in the official documentation specify a redirect_uri when doing both an access token and a refresh token exchange. However, this new guide makes do without for their access token exchange. Perhaps they missed it out? As this other stack overflow question says:
As an added measure of security, the server should verify that the redirect URL in this request matches exactly the redirect URL that was included in the initial authorization request for this authorization code. If the redirect URL does not match, the server rejects the request with an error.
I suppose this means that after the first access token exchange, any refresh token exchanges or straight up API requests with access tokens need to match the original redirect_uri of said first access token exchange. So I should use one and only one redirect_uri, and the refresh token exchanges/API requests do not actually use the redirect_uri, rather it's used for further security.
As for the whole login procedure, it seems I have to link the access & refresh tokens I obtain to a user session, and for that I'll look into using this passport strategy, passport-discord. Then, once the session expires, I'll discard the two tokens, and they'll have to click login again, but I can make use of this prompt option:
prompt controls how the authorization flow handles existing authorizations. If a user has previously authorized your application with the requested scopes and prompt is set to consent, it will request them to reapprove their authorisation. If set to none, it will skip the authorization screen and redirect them back to your redirect URI without requesting their authorization.
From there I think I'd just store the new access and refresh tokens associated with that user.
I'd really appreciate if any mistakes in my thought process could be pointed out!
Your summary seems good to me Mr Cloud - worth clarifying whether you are developing an SPA or (old) web app with a server side. Most commonly the first is cookieless, whereas the second stores a refresh token in a cookie. A key thing is to understand what the OAuth message workflow looks like. For SPAs and APIs this write up of mine may help you clarify what you want: https://authguidance.com/2017/09/26/basicspa-oauthworkflow/
Happy to answer any follow on questions ..
You can use the implicit grant to use with SPA
https://discord.com/developers/docs/topics/oauth2#implicit-grant

Hybrid Flow Web View Attacker Knows Redirect URL (IdentityServer4)

There is some confusion in my mind with the hybrid flow.
In this scenario, suppose we have a native desktop application that needs to authenticate a user. For such a case, we use the recommended hybrid flow.
As I understand it, we will use an embedded web browser to direct the user to the login page at the identity server. The user logs in successfully and the server redirects the web browser to the registered redirect url. The desktop application is notified of this redirect (something like an OnLoadFinished event) and parses the new url which contains some information including the authorization code. The desktop application then exchanges this authorization code for an access token/refresh token.
With this process in mind, is it not entirely possible that if a malicious user knows what the redirect url and client id is (lets pretend this user is an ex-employee), that they can create a very similar application like our desktop application to trick users into using that malicious application? Since they know both redirect url and client id, they can simulate the above process and get access/refresh tokens.
Am I correct in understanding that or is there something that I am missing?
You are absolutely correct. Just like with any other malware that a user installs on its machine/device.
This could also happen if someone applies reverse engineering in your application and gets your client_id + redirect, I guess.
Doesn't this mean that exposing client_id + redirect uri is as much dangerous as exposing client_id + client_secret in a public client?

OAuth 2.0 Single-use Access Token for unauthenticated user via IdentityServer4

I apologies in advance for incorrect use of oauth terms.
I have 4 "parties" as follows (intentionally not using oauth terms where possible):
End-user in a browser (javascript)
Our website (aspnet)
Our web api (aspnet)
Our auth server (aspnet utilising identityserver 4)
My usage scenario is that we only want the API to be called by a browser that has requested a page from the website first. Whilst the API doesn't release sensitive information, we would like to introduce a layer of complexity with regards to the API being spammed.
Our end user's will not be logged in.
I imagine such a flow being akin:
Browser requests a certain page from the website (one that will likely lead to js making an api call)
Website requests token from auth server
Auth server verifies token request came from website (the server itself)
Auth server returns a token to the website
Website returns page including the access token
Browser is able to make a request to api using token
Although convoluted, I believe this is at least similar to the Client Access Grant flow?
These tokens could then be throttled either by website or auth server.
Yes, I'm aware that this doesn't protect the api from numerous other vectors, but it does eliminate the simplest of cases which is all we're looking to achieve for now. I'll add, I didn't define this requirement, I'm simply trying to find a way to achieve it utilising techs out there instead of making the mistake of rolling anything of my own.
Could someone confirm/deny that there is an oauth flow I could use here? Any sample projects using the given flow and IdentityServer?
IdentityServer3 / non-aspnet[core/5] examples are fine, I can translate.
What you describe is the Client Credentials Grant where your website (client) gets an access token from identityserver (auth server). That access token can then be used to call endpoints on your web API (resource server).
The token is a bearer token and can be used by anyone who has it, so if you are comfortable with your website passing it back to a browser on an HTTP response, then it will work just fine.
I'm not sure what you mean by throttling the tokens - once minted they are valid for their lifetime. I guess you can keep the time-to-live very short to achieve the single usage you want though.

Dealing with expired access tokens in OAuth2 implicit grant

The specification of OAuth2 states that an authorization server must not issue a refresh token when using implicit grant. In our use case we protect a RESTful API with OAuth2 and use a Single Page Javascript application as a client for this API. As it would be very difficult to redirect to the authorization server after an access token has expired, we are searching for a better way to get a new valid token. I could think about two different approaches and wonder which one could be better:
Use a hidden iframe to Rerequest a valid access token. For this it is necessary to include a parameter like “prompt=none” which tells the OAuth provider neither to challenge authentication, nor to display an authorization page. If the user is authenticated and has authorized the application the server will send back an access token in the urls # parameters. If one of the previous conditions is not fulfilled, it will redirect with an error like #error=authentication%20lost. With this behaviour we can use short lived access tokens also with an implicit flow.
We could use an additional scope (e.g. offline) which tells the server to hand out a refresh token. Even if the original spec says that implicit flow does not issue refresh tokens (which is correct if the client only uses OAuth it for a first authorization) you are free to define your own scopes for your particular application. You should consider to only allow this scope from well-known clients.
Both approaches are very similar to those of OpenID Connect. Unfortunately there are not many implementations of OpenID Connect at the moment. So first step would be to extend the OAuth2 server until OIC will be more popular.
So which approach should be preferred?
EDIT: The token endpoint needs client authentication, which is only possible for confidential clients like server-side applications. With the second approach it would only be possible to let the RESTful API in our case the resource provider to refresh the token and send it back to the client. I think this would be a security risk. So probably we have only one valid approach.
I'm trying to achieve the exact same thing at the moment.
I've actually implemented hidden iframe approach and then realized you have to be very careful with iframes. Any malicious website can contain your iframe and get access token easily if you don't specify X-Frame-Options.
Best approach for refreshing token should be password grant as specified by the spec. (I wanted my users to login with their facebook account & implicit flow was easier to develop this. I have not quite figured out how to do this with password grant.)
2nd approach also came accross my mind and seems much safer than the 1st to me, since you can usually trust the https & browser storage to keep your tokens secret.
Edit
I realized, even with X-Frame-Options most browsers can't prevent redirects, because this header is attached to the response body and redirected URL will be exposed, therefore access tokens exposed.
Update
Looks like hash fragment is protected by the browser when accessed from the parent page within different domain. So I assume #access_token is safe. My bad. Just as a reminder callback page has to store the access token in its own right, instead of (my original intention) delegating it to the parent page like window.parent.storeAccessToken(hash); which obviously is a dumb thing to do.
From the OAuth0 website:
If you need to authenticate your users without a login page (for example, when the user is already logged in via SSO scenario) or get a new access_token (thus simulate refreshing an expired token), you can use Silent Authentication.
As for the Silent Authentication:
However, redirecting users away from your application is usually considered disruptive and should be avoided, from a UX perspective. Silent authentication lets you perform an authentication flow where Auth0 will only reply with redirects, and never with a login page.
This will allow you to log back the user using an SSO token, without having to prompt him for credentials again.

Getting started with OAuth

I wanted to build a simple WP7 app to learn how to use Silverlight, so I thought I'd create a very simple yammer app. As a starter it would have two screens - Login (Username & Password) and Feed.
Yammer user OAuth for its authentication but I just dont get it! i appreciate you need to request a token to use the REST interfaces, but I dont want my users (even if its just me) to need anything other than their login credentials, as they would use on the website. In my head the token can be used in a similar manner as a forms auth token in asp.net
Am I missing something? But I cant see anything in the yammer documentation about logging in.
The process for OAuth is as follows
You do a token request to Yammer. If needed they will ask for yammer credentials and send a token back to a URL of your application
You must use that token to sign all your petitions.
You can't stop Yammer asking for credentials because that's the idea of OAuth. Yammer does not trust you and it's impossible for you to keep any user Yammer's credentials. That way they can't be stolen from your site. The more you can store is a temporal token.
There is a very good guide to using OAuth on hueniverse, which features an example workflow. It's not completely up to date with the latest version of the spec, although this probably doesn't matter too much for your purposes.

Resources