Using Auth0 with oidc-client and PKCE - auth0

I'm using Auth0 with oidc-client (latest 1.10.1).
Now what I'm trying to do is to use PKCE flow instead of the implicit one and in AuthModule I have the following config for oidc:
NgOidcClientModule.forRoot({
// prettier-ignore
oidc_config: {
authority: environment.sts.authority,
client_id: environment.sts.clientId,
redirect_uri: `${environment.appRoot}oidc-login-redirect-callback.html`,
scope: 'openid profile email',
response_type: 'code',
post_logout_redirect_uri: `${environment.appRoot}oidc-logout-redirect-callback.html`,
silent_redirect_uri: `${environment.appRoot}oidc-silent-renew-redirect-callback.html`,
accessTokenExpiringNotificationTime: 10,
automaticSilentRenew: true,
metadata: {
authorization_endpoint: `${environment.sts.authority}authorize?audience=${environment.sts.audience}`,
userinfo_endpoint: `${environment.sts.authority}userinfo`,
issuer: environment.sts.authority,
jwks_uri: `${environment.sts.authority}.well-known/jwks.json`,
// tslint:disable-next-line:max-line-length
end_session_endpoint: `${environment.sts.authority}v2/logout?returnTo=${environment.appRootEncoded + 'oidc-logout-redirect-callback.html'}&client_id=${environment.sts.clientId}`
},
userStore: (() => new WebStorageStateStore({ store: window.localStorage })) as any
}
}),
I had to change response_type value from id_token toke to code.
Another thing I read that I need to change is in the static pages:
var config = {
userStore: new Oidc.WebStorageStateStore({ store: window.localStorage }),
response_mode: 'query',
};
var mgr = new Oidc.UserManager(config);
I understood that I need to add response_mode: 'query' for Oidc.UserManager config.
All good for now, but I think that I'm missing something because I'm infinitely redirected.
Are there some extra settings I need to do in Auth0 Application?

I found the solution: downgrade to oidc-client": "^1.8.2

Related

Nuxt Auth Module c5 doesn't refresh token automatically when token expires

Version
module: 5.0.0-1624817847.21691f1
nuxt: 2.15.8
Nuxt configuration
Universal
Nuxt configuration
// Auth: https://auth.nuxtjs.org/ (v5)
auth: {
redirect: {
login: '/account/login/',
logout: '/account/login/',
callback: '/account/login/',
home: '/account/beams/'
},
strategies: {
local: {
scheme: 'refresh',
token: {
property: 'access_token',
maxAge: 120, // seconds, 2 minutes
global: true
},
refreshToken: {
property: 'refresh_token',
data: 'refresh_token',
maxAge: 1209600 // seconds, 2 weeks
},
user: {
property: 'user',
autoFetch: true
},
endpoints: {
login: { url: '/api/account/login', method: 'post', propertyName: 'token' },
refresh: { url: '/api/account/refresh', method: 'post', },
logout: { url: '/api/account/logout', method: 'post' },
user: { url: '/api/account', method: 'get' }
},
autoLogout: false
}
}
},
Additional information
Checklist
[x] I have tested with the latest Nuxt version and the issue still occurs
[x] I have tested with the latest module version and the issue still occurs
[x] I have searched the issue tracker and this issue hasn't been reported yet
Steps to reproduce
What is expected?
When a user's token expires and refresh scheme is implemented, a user shouldn't be logged out and redirected back to the login screen, the refresh token should be used to obtain a new token and the transition should be seamless allowing any authenticated route to continue to work.
What is actually happening?
In my Nuxt project with the Auth module I've implemented the refresh scheme, however, when my token expires I don't see any request in my network being made to the refresh route after my token expires and I navigate to a protected page via the auth middleware.
I expect I'm missing some simple configuration?
My current token has an expiry of 1 minute for testing, and my refresh token has an expiry of 14 days for testing.
However, when adding:
scheme: 'refresh'
refresh: { url: '/api/account/refresh', method: 'post', }
the functionality appears to not be fetching my user and automatically logging me in.
My /api/account/refresh endpoint in my API returns the following:
{
refresh_token: 'my refresh token',
token_type: 'bearer',
expired_in: 5000
}
My /api/account/login endpoint in my API returns the following:
{
access_token: 'my token',
token_type: 'bearer',
expired_in: 1000
}
What am I missing?
You need to return refresh token from /api/account/login. And then set in conf property name of it.
I have same issue with very similar comfiguration. This is my result from API (I added refresh token to the result):
{
"access_token": "XXX",
"refresh_token": "XXX",
"expired_in": 3600,
"token_type": "bearer"
}
If I inspect cookies, I can see acces token, but refresh token does not set:
I try to manually set refresh token after login, but with same result:
const result = await this.$auth.loginWith('local', {
data: this.login,
})
this.$auth.setUserToken(result.data.accessToken, result.data.refreshToken)

how to generate access token on Shopify app without session

I develop a Shopify app and I used cookies based authentication for that.
sample code
server.use(session({ secure: true, sameSite: 'none' }, server));
server.use(
createShopifyAuth({
apiKey: SHOPIFY_API_KEY,
secret: SHOPIFY_API_SECRET_KEY,
scopes: ['read_products', 'write_products', 'read_themes', 'write_themes', 'read_script_tags', 'write_script_tags'],
async afterAuth(ctx) {
const { shop, accessToken } = ctx.session;
ctx.cookies.set('shopOrigin', shop, {
httpOnly: false,
secure: true,
sameSite: 'none'
});
// await login(ctx, accessToken, shop);
// await getScriptTag(ctx, accessToken, shop);
},
}),
)
Now, my problem is that it doesn't work on some browsers for cookies problems.
How can I use createShopifyAuth for generating access token without using cookies. if I comment server.use(session({ secure: true, sameSite: 'none' }, server)); it doesn't work any more.
I think you need to check the new JWT auth for cookies less authentication into the Shopify app.
Shopify Wiki Link

The 'offline_access' scope is not allowed when using OpenIdDict

Using Asp.Net Core 5.0 with Identity and OpenIdDict I have the following:
services.AddOpenIddict()
.AddCore(x => {
x.UseEntityFrameworkCore().UseDbContext<Context>().ReplaceDefaultEntities<Application, Authorization, Scope, Token, Int32>();
})
.AddServer(x => {
x.SetAuthorizationEndpointUris("/connect/authorize")
.SetLogoutEndpointUris("/connect/logout")
.SetTokenEndpointUris("/connect/token")
.SetUserinfoEndpointUris("/connect/userinfo");
x.RegisterScopes(OpenIddictConstants.Scopes.Profile, OpenIddictConstants.Scopes.Email, OpenIddictConstants.Scopes.OfflineAccess);
x.AllowAuthorizationCodeFlow();
x.AddDevelopmentEncryptionCertificate().AddDevelopmentSigningCertificate();
x.UseAspNetCore()
.EnableAuthorizationEndpointPassthrough()
.EnableLogoutEndpointPassthrough()
.EnableTokenEndpointPassthrough()
.EnableUserinfoEndpointPassthrough()
.EnableStatusCodePagesIntegration();
})
.AddValidation(x => {
x.UseLocalServer();
x.UseAspNetCore();
});
And I have the following client:
OpenIddictApplicationDescriptor spa = new OpenIddictApplicationDescriptor {
ClientId = "spa",
ClientSecret = "secret",
ConsentType = OpenIddictConstants.ConsentTypes.Implicit,
PostLogoutRedirectUris = {
new Uri("https://localhost:5002/oidc-signout")
},
RedirectUris = {
new Uri("https://localhost:5002/oidc-signin"),
new Uri("https://localhost:5002/oidc-silent-refresh")
},
Permissions = {
OpenIddictConstants.Permissions.Endpoints.Authorization,
OpenIddictConstants.Permissions.Endpoints.Logout,
OpenIddictConstants.Permissions.Endpoints.Token,
OpenIddictConstants.Permissions.GrantTypes.AuthorizationCode,
OpenIddictConstants.Permissions.GrantTypes.RefreshToken,
OpenIddictConstants.Permissions.ResponseTypes.Code,
OpenIddictConstants.Permissions.Scopes.Email,
OpenIddictConstants.Permissions.Scopes.Profile,
OpenIddictConstants.Permissions.Prefixes.Scope + "api"
},
Requirements = {
OpenIddictConstants.Requirements.Features.ProofKeyForCodeExchange
}
};
On the Angular Spa client application I am using the configuration:
const settings: UserManagerSettings = {
automaticSilentRenew: true,
authority: "https://localhost:5000",
client_id: 'spa',
client_secret: 'secret',
filterProtocolClaims: true,
loadUserInfo: true,
post_logout_redirect_uri: "https://localhost:5002/oidc-signout",
redirect_uri: "https://localhost:5002/oidc-signin",
response_mode: 'query',
response_type: 'code',
scope: 'openid profile email offline_access api',
silent_redirect_uri: 'https://localhost:5002/oidc-silent-refresh'
};
When I click on the SPA to login I am redirected and get the error:
The 'offline_access' scope is not allowed.
If I use it without 'offline_access' then everything works fine, e.g.:
scope: 'openid profile email api'
What am I missing?
The refresh token flow should be enabled before the offline_access scope can be used.
In your Startup.cs you should change this line:
x.AllowAuthorizationCodeFlow();
into something like this:
x.AllowAuthorizationCodeFlow().AllowRefreshTokenFlow();
There's also a GitHub issue related to your problem.

Invalid Grant error after being redirected to client application from OpenIdDict application

I have an application using OpenIdDict Beta 6 with ASP.NET Core 5.
I am using OpenIdDict Velusia sample and I have the following client:
OpenIddictApplicationDescriptor application = new OpenIddictApplicationDescriptor {
ClientId = "spa",
ClientSecret = "secret",
ConsentType = OpenIddictConstants.ConsentTypes.Implicit,
PostLogoutRedirectUris = {
new Uri("https://localhost:5002/oidc/signout")
},
RedirectUris = {
new Uri("https://localhost:5002/oidc/signin"),
},
Permissions = {
OpenIddictConstants.Permissions.Endpoints.Authorization,
OpenIddictConstants.Permissions.Endpoints.Logout,
OpenIddictConstants.Permissions.Endpoints.Token,
OpenIddictConstants.Permissions.GrantTypes.AuthorizationCode,
OpenIddictConstants.Permissions.GrantTypes.RefreshToken,
OpenIddictConstants.Permissions.ResponseTypes.Code,
OpenIddictConstants.Permissions.Scopes.Email,
OpenIddictConstants.Permissions.Scopes.Profile,
OpenIddictConstants.Permissions.Prefixes.Scope + "api"
},
Requirements = {
OpenIddictConstants.Requirements.Features.ProofKeyForCodeExchange
}
};
On my client application I am using OIDC Client and I have the following settings:
const settings: UserManagerSettings = {
automaticSilentRenew: true,
authority: "https://localhost:5000",
client_id: 'spa',
client_secret: "secret",
filterProtocolClaims: true,
loadUserInfo: true,
post_logout_redirect_uri: "https://localhost:5000/oidc/signout",
redirect_uri: "https://localhost:5000/oidc/signin",
response_mode: 'query',
response_type: 'code',
scope: 'openid profile email api'
};
I am able to login with email/password and to logout ...
When I login with Google I am redirected back to OpenIdDict application.
I get the successful login message and asked to confirm email to create the account.
I confirm it and I get redirected back to the spa client application ...
But when the OIDCClient-JS, in the spa, calls "/connect/token" I get the error:
Error: invalid_grant
It was working with previous OpenIdDict version ...
What am I missing?

Nuxt Auth - hide client_secret

When using the default laravel.passport strategy, I pass the client_secret and when I run npm run generate and search the generated code in dist, I can't find the client_secret; it's hidden, which is good and what I want.
However, when I use a custom strategy or local strategy and pass the client_secret, I can see the secret in the generated code in dist.
auth: {
strategies: {
password_grant_custom: {
_scheme: "~/auth/schemes/PassportPasswordScheme.js",
client_id: process.env.PASSPORT_PASSWORD_GRANT_ID,
client_secret: process.env.PASSPORT_PASSWORD_GRANT_SECRET,
endpoints: {
login: {
url: "/oauth/token",
method: "post",
propertyName: "access_token"
},
logout: false,
user: {
url: "api/v1/me",
method: 'get',
propertyName: false
}
}
},
'laravel.passport': {
url: "https://example.com",
client_id: process.env.PASSPORT_CLIENT_ID,
client_secret: process.env.PASSPORT_CLIENT_SECRET,
userinfo_endpoint: "https://example.com/api/v1/me",
}
}
},
How can I hide the client_secret so it's not visible in public code?
Because in laravel.passport its deleted after used when addAuthorize called. See code
// Get client_secret, client_id and token_endpoint
const clientSecret = strategy.client_secret
const clientID = strategy.client_id
const tokenEndpoint = strategy.token_endpoint
// IMPORTANT: remove client_secret from generated bundle
delete strategy.client_secret
So you need to do same for your scheme