Next Auth with Zitadel cloud: expected 200 OK, got: 301 Moved Permanently - next.js

Using next.js, next-auth with zitadel
import ZitadelProvider from "next-auth/providers/zitadel";
...
providers: [
ZitadelProvider({
issuer: process.env.ZITADEL_ISSUER,
clientId: process.env.ZITADEL_CLIENT_ID,
clientSecret: process.env.ZITADEL_CLIENT_SECRET,
})
]
...
And .env
NEXTAUTH_SECRET=random
NEXTAUTH_URL=http://localhost:3000
# Next Auth ZITADEL Provider
ZITADEL_CLIENT_ID=xyz#myproject
ZITADEL_CLIENT_SECRET=random
ZITADEL_ISSUER=https://myinstance-qz4usg.zitadel.cloud/
I get the following error when I try to sign in with zitadel
[next-auth][error][SIGNIN_OAUTH_ERROR]
https://next-auth.js.org/errors#signin_oauth_error expected 200 OK, got: 301 Moved Permanently {
error: {
message: 'expected 200 OK, got: 301 Moved Permanently',
stack: 'OPError: expected 200 OK, got: 301 Moved Permanently\n' +
' at processResponse (/Users/sdoxsee/workspace/simplestep/my-t3-app/node_modules/openid-client/lib/helpers/process_response.js:41:11)\n' +
' at Function.discover (/Users/sdoxsee/workspace/simplestep/my-t3-app/node_modules/openid-client/lib/issuer.js:152:20)\n' +
' at runMicrotasks (<anonymous>)\n' +
' at processTicksAndRejections (node:internal/process/task_queues:96:5)\n' +
' at async openidClient (/Users/sdoxsee/workspace/simplestep/my-t3-app/node_modules/next-auth/core/lib/oauth/client.js:16:14)\n' +
' at async getAuthorizationUrl (/Users/sdoxsee/workspace/simplestep/my-t3-app/node_modules/next-auth/core/lib/oauth/authorization-url.js:67:18)\n' +
' at async Object.signin (/Users/sdoxsee/workspace/simplestep/my-t3-app/node_modules/next-auth/core/routes/signin.js:38:24)\n' +
' at async AuthHandler (/Users/sdoxsee/workspace/simplestep/my-t3-app/node_modules/next-auth/core/index.js:253:26)\n' +
' at async NextAuthHandler (/Users/sdoxsee/workspace/simplestep/my-t3-app/node_modules/next-auth/next/index.js:23:19)\n' +
' at async /Users/sdoxsee/workspace/simplestep/my-t3-app/node_modules/next-auth/next/index.js:59:32\n' +
' at async Object.apiResolver (/Users/sdoxsee/workspace/simplestep/my-t3-app/node_modules/next/dist/server/api-utils/node.js:363:9)\n' +
' at async DevServer.runApi (/Users/sdoxsee/workspace/simplestep/my-t3-app/node_modules/next/dist/server/next-server.js:487:9)\n' +
' at async Object.fn (/Users/sdoxsee/workspace/simplestep/my-t3-app/node_modules/next/dist/server/next-server.js:749:37)\n' +
' at async Router.execute (/Users/sdoxsee/workspace/simplestep/my-t3-app/node_modules/next/dist/server/router.js:253:36)\n' +
' at async DevServer.run (/Users/sdoxsee/workspace/simplestep/my-t3-app/node_modules/next/dist/server/base-server.js:384:29)\n' +
' at async DevServer.run (/Users/sdoxsee/workspace/simplestep/my-t3-app/node_modules/next/dist/server/dev/next-dev-server.js:741:20)\n' +
' at async DevServer.handleRequest (/Users/sdoxsee/workspace/simplestep/my-t3-app/node_modules/next/dist/server/base-server.js:322:20)',
name: 'OPError'
},
providerId: 'zitadel',
message: 'expected 200 OK, got: 301 Moved Permanently'
}

Copying the issuer url from the .well-known/openid-configuration endpoint put a trailing '/' at the end of my issuer (as can be seen in my .env above).
Removing the '/' fixed it.
i.e. ZITADEL_ISSUER=https://myinstance-qz4usg.zitadel.cloud

Related

How to resolve 'getUserByAccount is not a function' in next-auth?

I've updated Nextjs to it's newest version and also updated next-auth and the prisma adapter as specified by the docs.
However, when I try to authenticate in the app with signIn I get the following error with the latest updates:
[next-auth][error][OAUTH_CALLBACK_HANDLER_ERROR]
https://next-auth.js.org/errors#oauth_callback_handler_error getUserByAccount is not a function {
message: 'getUserByAccount is not a function',
stack: 'TypeError: getUserByAccount is not a function\n' +
' at Object.callback (/home/.../node_modules/next-auth/core/routes/callback.js:81:39)\n' +
' at runMicrotasks (<anonymous>)\n' +
' at processTicksAndRejections (internal/process/task_queues.js:95:5)\n' +
' at async NextAuthHandler (/home/.../node_modules/next-auth/core/index.js:103:28)\n' +
' at async NextAuthNextHandler (/home/.../node_modules/next-auth/next/index.js:40:7)\n' +
' at async [...]/node_modules/next-auth/next/index.js:80:32\n' +
' at async Object.apiResolver (/home/.../node_modules/next/dist/server/api-utils.js:102:9)\n' +
' at async DevServer.handleApiRequest (/home/.../node_modules/next/dist/server/next-server.js:1014:9)\n' +
' at async Object.fn (/home/.../node_modules/next/dist/server/next-server.js:901:37)\n' +
' at async Router.execute (/home/.../node_modules/next/dist/server/router.js:210:32)',
name: 'TypeError'
}
Is there something I'm doing wrong, or is there an incompatibility I'm missing?
Relevant package.json:
...
"#next-auth/prisma-adapter": "^0.5.2-next.19",
"next": "^12.0.3",
"next-auth": "4.0.0-beta.6",
"prisma": "^3.4.1",
...
[...nextauth].ts:
import NextAuth from 'next-auth';
import CognitoProvider from 'next-auth/providers/cognito';
import { PrismaAdapter } from '#next-auth/prisma-adapter';
import { PrismaClient } from '#prisma/client';
const prisma = new PrismaClient();
export default NextAuth({
adapter: PrismaAdapter(prisma),
providers: [
CognitoProvider({
clientId: process.env.COGNITO_CLIENT_ID,
clientSecret: process.env.COGNITO_CLIENT_SECRET,
issuer: process.env.COGNITO_ISSUER,
}),
],
callbacks: {
async session({ session, user }) {
session.userId = user.id;
session.role = user.role;
return Promise.resolve(session);
},
},
});
Finally resolved the problem. Since next-auth has moved to monorepo, updating package was not enough, you need to uninstall it first then install it again.
Run:
npm uninstall next-auth #next-auth/prisma-adapter
then:
npm install #next-auth/prisma-adapter
This fixed it for me.
In the NextAuth.JS 4.0 the "Prisma schema" have slightly changed.
From the upgrade guide:
created_at/createdAt and updated_at/updatedAt fields are removed from all Models.
user_id/userId consistently named userId.
compound_id/compoundId is removed from Account.
access_token/accessToken is removed from Session.
email_verified/emailVerified on User is consistently named email_verified.
provider_id/providerId renamed to provider on Account
provider_type/providerType renamed to type on Account
provider_account_id/providerAccountId on Account is consistently named providerAccountId
access_token_expires/accessTokenExpires on Account renamed to expires_in
New fields on Account: expires_at, token_type, scope, id_token, session_state
verification_requests table has been renamed to verification_tokens
Complete new schema in:
https://next-auth.js.org/adapters/prisma

How to send a get Request in AL

I currently have 2 problems. I am trying to send a GetRequest to my web service. This is done with the SendNotify (phonenumber: text; template: text) method. When I call the method via an action, I get the following error message: Misused header name. Make sure request headers are used with HttpRequestMessage, response headers with HttpResponseMessage, and content headers with HttpContent objects.
When I debug, the program stops at the following line: ContentHeaders.Add('Authorization', 'Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiI2dsadaXdrZUZTTWpNcnlBc2s1IiwiZXhwIjoxNTk1NDA3NDgzLCJpYXQiOjE1OTQzNjgyNTR9.1tAsf-x2FEvhDMyB4dsvgVKfZMLwAHcr_OLRA8RBeiY');
The token is currently hard coded but should be removed from the service setup list.
Can anyone tell me what I am doing wrong?
codeunit 2020803 "Notify SMS Interface" implements SendNotifyInterface
{
procedure CheckInputData(NotifyEntry: Record "Notify Entry")
begin
NotifyEntry.Get();
end;
procedure SendNotify(phonenumber: text; template: text)
var
client: HttpClient;
RequestMessage: HttpRequestMessage;
RequestHeaders: HttpHeaders;
ResponseMessage: HttpResponseMessage;
NotifyServiceSetup: Record "Notify Service Setup";
JsonText: Text;
IsSuccessful: Boolean;
SendSMSURL: text;
begin
NotifyServiceSetup.Get();
SendSMSURL := NotifyServiceSetup."Service URL" + '/contacts/contacts/sms/' + 'sagos/' +
phonenumber + '/' + template;
JsonText := BuildJsonText();
InitHttpRequestContent(RequestMessage, JsonText);
InitHttpRequestMessage(RequestMessage, SendSMSURL, 'GET');
IsSuccessful := client.Send(RequestMessage, ResponseMessage);
if not IsSuccessful then
Error('Authentication failed!');
if not ResponseMessage.IsSuccessStatusCode then begin
Error('request was not successfully');
exit;
end;
end;
local procedure InitHttpRequestContent(var RequestMessage: HttpRequestMessage; JsonText: Text)
var
ContentHeaders: HttpHeaders;
NotifyServiceSetup: Record "Notify Service Setup WMR";
bearerToken: Text[250];
token: Text[250];
begin
token := NotifyServiceSetup.GetToken(NotifyServiceSetup."Authentication Token Key");
bearerToken := 'Bearer ' + token;
NotifyServiceSetup.Get();
RequestMessage.Content().Clear();
RequestMessage.Content().WriteFrom(JsonText);
RequestMessage.Content().GetHeaders(ContentHeaders);
ContentHeaders.Clear();
ContentHeaders.Add('Content-Type', 'application/json');
ContentHeaders.Add('Authorization', 'Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiI2dsadaXdrZUZTTWpNcnlBc2s1IiwiZXhwIjoxNTk1NDA3NDgzLCJpYXQiOjE1OTQzNjgyNTR9.1tAsf-x2FEvhDMyB4dsvgVKfZMLwAHcr_OLRA8RBeiY');
end;
local procedure InitHttpRequestMessage(var RequestMessage: HttpRequestMessage; ServiceURL: Text; Method: Text)
var
RequestHeaders: HttpHeaders;
NotifyServiceSetup: Record "Notify Service Setup WMR";
token: Text[250];
bearerToken: Text[250];
begin
token := NotifyServiceSetup.GetToken(NotifyServiceSetup."Authentication Token Key");
bearerToken := 'Bearer ' + token;
RequestMessage.GetHeaders(RequestHeaders);
RequestHeaders.Clear();
RequestHeaders.Add('Accept', 'application/json');
RequestHeaders.Add('Authorization', 'Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiI2dXdrZUZTTWpNcnlBc2s1IiwiZXhwIjoxNTk1NDA3NDgzLCJpYXQiOjE1OTQzNjgyNTR9.1tAsf-x2FEvhDMyB4dsvgVKfZMLwAHcr_OLRA8RBeiY');
RequestMessage.Method(Method);
RequestMessage.SetRequestUri(ServiceURL);
end;
local procedure BuildJsonText() ContentText: Text
var
ContentJson: JsonObject;
begin
ContentJson.WriteTo(ContentText);
end;
}
The second problem I have is checking the data in the CheckInputData (NotifyEntry: Record "Notify Entry") method. There is a field in the Notify Entry called Contact No. that has all the information about the customer. I want to ask in the method to have the phone number and the salutation available. Unfortunately I do not know how I got out of Contact No. Can request data. Would someone have a tip?
UPDATE 1
codeunit 2020808 Test
{
procedure sendNotify(phonenumber: text; template: text)
var
NotifyServiceSetup: Record "Notify Service Setup WMR";
IsSuccessful: Boolean;
client: HttpClient;
content: HttpContent;
contentHeaders: HttpHeaders;
request: HttpRequestMessage;
response: HttpResponseMessage;
txtResponse: InStream;
Url: Text;
token: Text[250];
begin
NotifyServiceSetup.Get();
token := NotifyServiceSetup.GetToken(NotifyServiceSetup."Authentication Token Key");
content.GetHeaders(contentHeaders);
contentHeaders.Clear();
contentHeaders.Add('Content-Type', 'application/json');
request.GetHeaders(contentHeaders);
contentHeaders.Add('Authorization', StrSubstNo('Bearer %1', token));
request.Content := content;
Url := NotifyServiceSetup."Service URL" + '/contacts/contacts/sms/' + 'Tegos/' + phonenumber + '/' + template;
request.SetRequestUri(Url);
request.Method := 'GET';
client.Send(request, response);
response.Content().ReadAs(txtResponse);
end;[![enter image description here][1]][1]
If the problem seems to be in the contentHeader.Add() This happened to me too.
I leave you this code for you to take as a reference.
procedure CheckCodeWebService(_accessToken: Text; _salesHeader: record "Sales Header")
var
jsonRequest: Text;
txtResponse: InStream;
Url: Text;
client: HttpClient;
request: HttpRequestMessage;
response: HttpResponseMessage;
contentHeaders: HttpHeaders;
content: HttpContent;
begin
jsonRequest := '{' +
'"GetPurchaseOrder": {' +
'"value": {' +
'"DataArea": {' +
'"PurchaseOrder": [' +
'{' +
'"PurchaseOrderHeader": {' +
'"ID": {' +
'"value": ""' +
'},' +
'"DocumentReference": [' +
'{' +
'"ID": {' +
'"value": " ' + _salesHeader.DealID + ' "' +
'}' +
'}' +
'],' +
'"SalesOrderReference": [' +
'{' +
'"ID": {' +
'"value": " ' + _salesHeader.SalesOrderNroCisco + ' "' +
'}' +
'}' +
'],' +
'"Description": [' +
'{' +
'"value": "yes",' +
'"typeCode": "details"' +
'}' +
']' +
'}' +
'}' +
']' +
'},' +
'"ApplicationArea": {' +
'"CreationDateTime": "datetime",' +
'"BODID": {' +
'"value": "BoDID-test",' +
'"schemeVersionID": "V1"' +
'}' +
'}' +
'}' +
'}' +
'}';
content.WriteFrom(jsonRequest);
content.GetHeaders(contentHeaders);
contentHeaders.Clear();
contentHeaders.Add('Content-Type', 'application/json');
request.GetHeaders(contentHeaders);
contentHeaders.Add('Authorization', StrSubstNo('Bearer %1', _accessToken));
contentHeaders.Add('Accept', 'application/xml');
request.Content := content;
Url := 'https://api.xxxx.com/xxxxx/ORDER/v2/sync/xxxxxxxx';
request.SetRequestUri(Url);
request.Method := 'POST';
client.Send(request, response);
response.Content().ReadAs(txtResponse);
Okay problem solved. Instead of the content type I have now entered RequestHeaders.Add ('Accept', 'application / json'). Now the GetRequest works.
codeunit 2020808 Test
{
procedure sendNotify(phonenumber: text; template: text)
var
NotifyServiceSetup: Record "Notify Service Setup WMR";
IsSuccessful: Boolean;
client: HttpClient;
content: HttpContent;
contentHeaders: HttpHeaders;
request: HttpRequestMessage;
response: HttpResponseMessage;
txtResponse: InStream;
Url: Text;
token: Text[250];
begin
NotifyServiceSetup.Get();
token := NotifyServiceSetup.GetToken(NotifyServiceSetup."Authentication Token Key");
content.GetHeaders(contentHeaders);
contentHeaders.Clear();
//contentHeaders.Add('Content-Type', 'application/json');
request.GetHeaders(contentHeaders);
contentHeaders.Add('Authorization', StrSubstNo('Bearer %1', token));
contentHeaders.Add('Accept', 'application/json');
//request.Content := content;
Url := NotifyServiceSetup."Service URL" + '/contacts/contacts/sms/' + 'Tegos/' + phonenumber + '/' + template;
request.SetRequestUri(Url);
request.Method := 'GET';
client.Send(request, response);
response.Content().ReadAs(txtResponse);
end;
}

response of react native get request gets status text undefined

I'm new to React Native and I'm calling an API with params. It looks like this.
async onSendClick() {
AsyncStorage.getItem('#Token:key').then((token) => {
console.log("console is " + token)
let subject = "Feedback Form"
let senderEmail = 'test#test.com'
let fromEmail = 'us#test.com'
let replyTo = 'customer#test.com'
let url = BASE_URL + '/email/send?'
let params = "subject=" + subject + "&email=" +senderEmail + "&fromEmail=" + fromEmail + "&replyTo=" + replyTo + "&content=" + feedBackMessage
return fetch(url + params , {
method: 'GET',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + token
},
}).then((responseOne) => {
console.log(responseOne)
if (responseOne.status == 200) {
console.log("success")
} else{
console.log("error")
}
}).catch((error) => console.error("ERROR" + error));
})
}
In the response section , I'm getting 404 error with statusText: undefined. Please help me to fix this issue.
You must encode the URI. Otherwise it will not work.
Follow this link for more info about URL encoding in javascript.

angular2 basic authorization on get request - 405

I'm trying to get basic authorization to work for a Get request, but I'm getting 2 exceptions:
OPTIONS http://localhost/drupal/user/1?_format=json
XMLHttpRequest cannot load http://localhost/drupal/user/1?_format=json. Response for preflight has invalid HTTP status code 405
I'm using angular2 with drupal 8 backend
here is my service
var _baseUrl = "http://localhost/drupal";
#Injectable()
export class DrupalService {
private actionUrl: string;
constructor(private _http: Http, private _apiUrl: DrupalApi) {
this.actionUrl = _baseUrl + _apiUrl;
}
authHeaders() {
let username = 'username';
let password = 'password';
let token = btoa(username + ':' + password);
var headers = new Headers();
headers.append('Authorization', 'Basic ' + token);
headers.append('Content-Type', 'application/json');
headers.append('Accept', 'application/json');
return headers;
}
public GetSingle = (id: number): Observable<Response> => {
return this._http.get(this.actionUrl + id + '?_format=json'
, {headers: this.authHeaders()}).map(res => res.json());
}
}
but it works when I try the same request from postman app
how can I fix it?
In Postman, you are sending a header:
Authorization: Basic bXVyaGFmOmhleGFkZWNpbWFsMDU
But in angular you are passing:
headers.append('Authorization', 'Basic ' + btoa('bXVyaGFmOmhleGFkZWNpbWFsMDU'));
which will end up being:
Authorization: Basic YlhWeWFHRm1PbWhsZUdGa1pXTnBiV0ZzTURV
So, just don't convert the string to base64
headers.append('Authorization', 'Basic bXVyaGFmOmhleGFkZWNpbWFsMDU');
Update
Error code 405 means : Method Not Allowed, Which means, drupal does not allow OPTIONS requests. I've not worked with Drupal before. But, there should be a way to allow OPTIONS requests.

Can't get the token of the Google account

I follow the instruction to send the id token of the Google account to the back end server to be authenticated but it seems like the token does not exist.
function onSignIn(googleUser) {
var profile = googleUser.getBasicProfile();
var id_token = googleUser.getAuthResponse().id_token;
console.log('ID: ' + profile.getId()); // Do not send to your backend! Use an ID token instead.
console.log('Name: ' + profile.getName());
console.log('Image URL: ' + profile.getImageUrl());
console.log('Email: ' + profile.getEmail());
console.log('Token: ' + id_token);
}
The line Token: is not printed in the console. Anybody could tell me what's going on? Much appreciated

Resources